Version History
144 releases-
v3.7.0.27 Stable May 20, 2026Download v3.7.0.27📦 9.16 MB⚙️ WP 5.2+🔧 PHP 7.2+✓ Tested 6.4
AuctionForge Changelog
All notable changes to the AuctionForge plugin are documented in this file.
---
[3.7.0.21] — 2026-05-05
Added — Connection Diagnostics on the Updates admin page
A new Connection Diagnostics card on Lots → Updates that detects and one-click-heals identity mismatches between this site and the deployment server.
The problem it solves. When a WordPress install is cloned (template → customer site, dev → prod, backup → restore), the cloned wp_options carry the original site's
auctionforge_update_api_keyover to the newhome_url(). The new install then makes API calls to wpdeploy *authenticated as the original site*. wpdeploy looks up by api_key, not by URL, so every/sync-user-tracking,/check-updates,/report-health, and most importantly the Kuma push URL, gets recorded against the WRONGwpdeploy.sitesrow. The cloned site's monitor stays silent; the original's monitor shows traffic that isn't from it.What the diagnostic does:
- Run Identity Check — calls the new wpdeploy
GET /api.php/whoamiendpoint and compares the returnedcaller_site_urlagainsthome_url(). Renders a verdict ("matches" / "MISMATCH") plus the full server-side view (site_id, site_name, last_check, plugin version on file, remote IP). The "Re-register & Reset Kuma" button only appears if there's a mismatch. - Re-register & Reset Kuma — calls
/request-access(which is idempotent onsite_url— wpdeploy returns the canonical api_key for *this*home_url(), regardless of whatever wrong key we were holding), wipesauctionforge_kuma_push_urland any leftover heartbeat cron events, then immediately fires/check-updatesso the api_request interceptor catches the freshly-correct kuma_push_url for *this* site. The keepalive mu-plugin's heartbeat picks it up on the next 60s tick.
Internal
AuctionForge_Auto_Updater::whoami()(new) — thin wrapper overapi_request('whoami', [], 'GET'). Returns the parsed wpdeploy/whoamipayload.AuctionForge_Auto_Updater::reset_connection()(new) — three-step heal: re-register → wipe Kuma cached state → re-fetch via/check-updates. Returns shape suitable forwp_send_json_success.- Two new AJAX actions:
auctionforge_diagnose_connection,auctionforge_fix_connection. Both behindmanage_optionscapability + nonce check. auctionforge_normalize_host()helper for case/scheme/www-tolerant URL comparison.
Server-side companion
Requires the wpdeploy
/api.php/whoamiendpoint added in the same release window. The endpoint is gated behind whatever api_key the caller already presented (a master key returnstype=masterwith no site row; a per-site key returns the site row that key resolves to). Reveals nothing the caller doesn't already implicitly authenticate against.---
[3.7.0.20] — 2026-05-04
Changed
- Kuma heartbeat path is now wpdeploy-independent. The actual heartbeat firing — wp-cron schedule, page-load piggy-back, outbound HTTP — moved out of AF and into the AuctionForge Keepalive mu-plugin (
wp-content/mu-plugins/auctionforge-keepalive.php, bumped to v1.2.1). Once a site has been provisioned once andauctionforge_kuma_push_urlis cached locally, the heartbeat keeps reporting forever even if AF is deactivated, mid-upgrade, deleted from disk, or wpdeploy is offline. The mu-plugin can't be deactivated by WordPress, can't be broken by an AF release, and depends on AF for nothing. - AF only writes the
kuma_push_urloption now. It no longer schedules the cron, no longer fires the heartbeat, and no longer holds any heartbeat-related state. Theapi_request()interceptor still catcheskuma_push_urlfrom/check-updatesand/report-healthresponses and persists it; the mu-plugin reads it from there. - Migration block.
init_hooks()clears any leftoverauctionforge_kuma_heartbeatwp-cron event from AF ≤ 3.7.0.19 on first plugin load after upgrade. The mu-plugin runs the same clear on its ownplugins_loadedhook — belt and braces. The new event the mu-plugin schedules iskuma_heartbeat_tickon a newkuma_60sschedule. AuctionForge_Auto_Updater::kuma_heartbeat()no-opped. Kept as a safety landing pad so any staleauctionforge_kuma_heartbeatwp-cron event that fires one last time before migration kicks in doesn't trip a "no callback registered" warning. Real heartbeat work happens in the mu-plugin.
Added — operator override
AUCTIONFORGE_KUMA_PUSH_URLconstant. Define it inwp-config.phpto point a site directly at Kuma without ever involving wpdeploy:
```php
define('AUCTIONFORGE_KUMA_PUSH_URL', 'https://kuma.example.com/api/push/<token>?status=up&msg=&ping=');
```
The constant takes precedence over the
auctionforge_kuma_push_urloption. With it set, the site can be operated fully outside wpdeploy — useful for one-off installs, customer-managed sites, or disaster-recovery scenarios where wpdeploy is unreachable for an extended period.Internal — Keepalive mu-plugin v1.2.1
The bundled keepalive template at
inc/keepalive/auctionforge-keepalive.template.phpnow also handles Kuma heartbeats. Three layered triggers ensure cadence stays tight regardless of site traffic:1. Dedicated wp-cron event
kuma_heartbeat_tickon a new 60-secondkuma_60sschedule2. Page-load piggy-back on
init: any request older than 50s since the last beat fires another, transient-guarded so concurrent hits coalesce. Free on busy sites; rescues low-traffic sites the moment any visitor arrives.3. Self-heal inside the cron callback: if the event somehow gets cleared, re-arm it before sending the beat.
HTTP is
timeout=2, blocking=false— fire-and-forget, never slows page loads. External IP introspection (ipify → ifconfig.me → icanhazip fallback chain, 24h transient cache) is duplicated in the mu-plugin so it doesn't depend on AF being loaded for the IP lookup.The keepalive installer (
class-keepalive-installer.php) detects theKEEPALIVE_VERSION: 1.2.1header bump and idempotently overwrites every site's mu-plugin on the next AF load. No manual reactivation needed.Failure modes after this release
| State | Heartbeat? |
|---|---|
| AF active and healthy | ✅ via mu-plugin |
| AF deactivated by an operator | ✅ mu-plugin runs anyway |
| AF deleted from disk | ✅ as long as
auctionforge_kuma_push_urloption exists OR constant is set || AF mid-upgrade / partial install | ✅ mu-plugin doesn't depend on AF code paths |
| wpdeploy down (existing site) | ✅ option is cached locally, no wpdeploy round-trip |
| wpdeploy down (brand-new site, never provisioned) | ❌ first-time URL provisioning still needs wpdeploy. One-shot, accepted trade-off. |
| Site has zero traffic AND wp-cron isn't firing | ❌ truly nothing to trigger a beat. Mitigation is OS-level cron / DISABLE_WP_CRON, out of scope here. |
---
[3.7.0.19] — 2026-05-04
Changed
- Reverted Kuma heartbeat cadence: 3 min → 1 min.
auctionforge_kuma_heartbeatis back on thebp_minutelyschedule. With Kuma's 310s silence window, 60s cadence tolerates 4 missed wp-cron ticks before flipping a monitor red — the original "give-it-leeway" semantics. The 3-min cadence introduced in 3.7.0.18 was strictly less chatty but tighter (a single missed tick would trip Kuma), and the trade-off wasn't worth it operationally. - Migration block updated.
init_hooks()now detects any existing event scheduled on a non-bp_minutelycadence (e.g. thebp_3_minutelyset by 3.7.0.18) and re-schedules ontobp_minutely. Sites that took 3.7.0.18 roll back automatically on first plugin load after upgrade. - First-fire jitter narrowed back to 0–60s to match the new cadence.
Notes
- The
bp_3_minutelycron schedule registration inauctionforge.phpis kept (harmless; available for future use). Only the heartbeat scheduling sites have been reverted. - Apparent latency in Kuma flipping a monitor red after a real outage is governed by Kuma's per-monitor
interval(silence-detection window, currently 310s on the wpdeploy/Kuma side), not by this cron's cadence. To detect outages faster, lower the Kumainterval; to add more tolerance to wp-cron drift, raise it.
---
[3.7.0.18] — 2026-05-04
Changed
- Kuma heartbeat cron cadence: 1 min → 3 min.
auctionforge_kuma_heartbeatnow runs on a newbp_3_minutelyschedule (180s) instead ofbp_minutely(60s). This pairs with Kuma's 310s silence-detection window — a single late wp-cron tick (3 min + drift) still lands inside the threshold, but normal traffic to Kuma drops by ~3×. - Random first-fire offset widened from 60s → 180s. With ~50 sites on a single Kuma instance, spreading first-fires across the full 3-min window prevents synchronised bursts every 3 minutes.
- Auto-migration of existing scheduled events. On plugin upgrade
init_hooks()callswp_get_scheduled_event('auctionforge_kuma_heartbeat')and, if the existing event is onbp_minutely, clears it and reschedules ontobp_3_minutely. Idempotent — a no-op once migrated.
Internal
- New cron schedule registered:
bp_3_minutely(BP_MINUTELY * 3= 180s). Defined alongside the existingbp_minutely/bp_ten_minutely/bp_hourly/bp_24_hourlyschedules inauctionforge.php.
---
[3.7.0.17] — 2026-05-04
Fix: "Install Now" always returned
up_to_dateThe
/sync/versionREST endpoint (called by wpdeploy's Install Now button) was always respondingsuccess: false, reason: up_to_dateregardless of the actual installed version, defeating the button's whole purpose.Root cause
rest_force_plugin_update()did:```
delete_site_transient('update_plugins');
$this->check_pending_updates();
$updates = get_site_transient('update_plugins');
```
check_pending_updates()calls the/pending-updatesendpoint on wpdeploy (which returns the deploy queue), but it does not touch the WPupdate_pluginstransient. The transient just got deleted on the line above and never gets re-populated, so theisset($updates->response[…])check always failed → always returnedup_to_date.Fix
- Use
wp_update_plugins()instead — that's what fires thepre_set_site_transient_update_pluginsfilter chain that AF's owncheck_for_updates()callback hooks into to seed the transient. Same pattern is already used correctly ininstall_update()at line 280. - Belt-and-braces: when the request body carries an explicit target
versionand that version is strictly greater than the on-disk plugin version (perversion_compare), bypass the transient check and force the install. This handles edge cases where the transient seeding fails (network blip during the wp-cron cycle, hosting-side cache, etc.) so the explicit Install Now command still does what it says.
---
[3.7.0.16] — 2026-05-04
Server external IP reported to wpdeploy + included in Kuma heartbeats
Each AF install now reports its server's outbound external IP. Two channels:
1. Kuma heartbeat
msg— the per-minute push payload now reads<wp_version>|<plugin_version>|<external_ip>(e.g.6.9.4|3.7.0.16|152.53.187.82) so you can spot at a glance which physical box each site lives on. When a host goes dark, multiple monitors flip red simultaneously with the same IP — instant root-cause hint.2.
/report-healthpayload — a newexternal_ipfield that wpdeploy stores onsites.external_ip. Visible in the Sites admin view as a tappable IP chip; clicking it filters the table to all sites sharing that IP.How the IP is detected
AuctionForge_Auto_Updater::get_external_ip()calls one of three public echo services in turn —api.ipify.org,ifconfig.me/ip,icanhazip.com— with a 4-second timeout each. The first one that returns a valid IP wins. Result is cached in a transient for 24 hours so we don't hit external services on every report cycle.Wpdeploy fallback for older plugins
/report-healthnow also capturesREMOTE_ADDR(orHTTP_CF_CONNECTING_IPwhen behind Cloudflare) when the payload doesn't includeexternal_ip. So sites still on 3.7.0.15 or older start populating their IP today via the same route, no plugin update needed for that data path.---
[3.7.0.15] — 2026-05-04
Kuma monitors land in an "Unallocated" group by default
New AuctionForge installs are auto-enrolled into Kuma under a new top-level group called Unallocated so the operator can review them and drag-drop into the right home (Bidspirit Auction Sites, Stephen's Auctions, Misc Websites, etc.) before classification. Without this every new monitor would appear at the dashboard top level alongside whatever group hierarchy already exists.
What changed (wpdeploy-side, no plugin behaviour change)
KumaProvisionernow ensures an "Unallocated" group exists in Kuma (find-or-create via the same Socket.IOaddpath used for monitors, withtype='group') before provisioning each new push monitor, and passesparent=<group_id>in theaddpayload so the new monitor lands inside it.- The Node helper accepts arbitrary
typeandparentfields on the input payload (previously hardcoded totype='push'). - The group itself gets the same
user_id=1reassignment so it shows up on the human admin's dashboard.
Existing Clumber monitor (id=71) was migrated into the new group as part of this release.
This is a wpdeploy infrastructure change — the AF plugin code is unchanged from 3.7.0.14. Version bumped only to mark a clean snapshot point.
---
[3.7.0.14] — 2026-05-04
Uptime Kuma push heartbeat with automatic enrolment
Each AF install now appears as its own monitor on the central Uptime Kuma at https://kuma.smoothbyteit.dev, beating every minute and flipping red within ~90 seconds when a site goes dark. Auto-enrolled — no manual Kuma UI clicks per site.
How it works
1. First contact: when the plugin calls
/request-accessor/report-health, wpdeploy's newKumaProvisioneropens a Socket.IO connection to Kuma as a dedicatedauctionforge-botuser, calls the officialaddevent, and gets back a fresh push token. The resulting URL is shipped to the plugin in the JSON response askuma_push_url.2. Plugin-side: a generic interceptor on
api_request()persistskuma_push_urlto the optionauctionforge_kuma_push_urlwhenever it appears in any wpdeploy response, and immediately schedules the newauctionforge_kuma_heartbeatcron on the existingbp_minutelyinterval.3. Heartbeat: the cron handler sends a single
wp_remote_getto the push URL each minute withmsg=<wp_version>|<plugin_version>so Kuma's dashboard shows the running stack at a glance. Kuma's silence-detection window is 90s, so a single missed wp-cron tick won't false-DOWN.4. Idempotency: the Kuma monitor's
descriptionfield storeswpdeploy_site_id:<id>. Re-registering the same site short-circuits at the wpdeploy layer (existingkuma_monitor_idonsites), or — if that's missing — Kuma's existing row is reattached via the description anchor. Re-installing the plugin never duplicates monitors.Why Socket.IO and not direct DB insert
Kuma's monitor scheduler does not poll its own DB for new rows —
startMonitors()only loads monitors at boot, and new ones are armed via the authenticated Socket.IOaddevent handler (which callsstartMonitor()and arms the per-monitorsafeBeatsetTimeout). A direct INSERT would create a "phantom" monitor that accepts pushes but never flips DOWN on silence, defeating the whole feature.Notifications + monitor ownership
Provisioner reads existing Kuma notification rows whose channel is Telegram (or marked default-for-new-monitors) and attaches them to every new monitor via the
addevent'snotificationIDList. After the Socket.IOaddsucceeds, the provisioner direct-writesuser_id=1to the new monitor row in Kuma's SQLite — Kuma'saddhandler hardcodesuser_id=socket.userID(the bot at user 2), which causes the frontend's real-time monitor-list updates to skip the admin's session. The follow-up UPDATE stamps ownership to the human admin so monitors render with their full name on the admin dashboard immediately.Failure modes
Every call boundary degrades safely. If Kuma is unreachable when a site registers, registration completes without
kuma_push_url; the next twicedaily/report-healthretries. Heartbeat HTTP failures are silent (which is the desired outcome — Kuma's silence-detection is the signal). Kuma reset / monitor row deleted: provisioner's pre-flight check NULLs the wpdeploy anchors and falls through to fresh provisioning on the next call.Operator setup
Already done: the
auctionforge-botKuma user has been created and credentials populated in wpdeploy'sconfig.php. To rotate or migrate Kuma later, editKUMA_URL/KUMA_BOT_USER/KUMA_BOT_PASSinconfig.php— no plugin redeploy needed.---
[3.7.0.13] — 2026-05-04
Wide shortcode: hide Register button for logged-in users
- When a user is logged in to BidSpirit (
body.bp-login), the Register button is now automatically hidden on wide-format auction cards (bp_upcoming_wideandbp_auction_list layout="wide"). - The View Catalog / Catalog Coming Soon button expands to full width when the Register button is hidden.
- Uses a lightweight
MutationObserverto react to BidSpirit's async session init. - Applied to both
UpcomingAuctionWide.phpandAuctionList.phpshortcode CSS blocks.
---
[3.7.0.12] — 2026-05-03
Stop-word denylist for BidSpirit category-tag concatenations
BidSpirit's
wp_bp_meta_data.tagsfield arrives as PascalCase category names lowercased without separators (uscollectibles,firearmsaccessoriesammunition,usdecorativearts,printsandmultiples). They look like keywords but they're really categories, and on sites where the tags field is populated they completely swamp the top-5 chips for power users (e.g. one buyer's profile was led byuscollectibles 453 viewsdespite that being a label rather than a real interest signal).29 known patterns added to
stop-words.phpso the tokenizer drops them at extraction time. New ones surfacing from sites we haven't seen yet should be added here as they appear; the wpdeploy?tab=keywordscorpus page makes them easy to spot (sort by most users with low lots count and look for non-word concatenations).---
[3.7.0.11] — 2026-05-03
Keyword extractor — capture model years + hyphenated calibers, drop more auction noise
The People view's top-5 keyword chips were filling up with generic descriptors (
household,model,original,assortment) instead of the brand/maker terms (mauser,whitworth,colt) that actually distinguish one buyer from another. Live-data review on the new?tab=keywordsKeyword Corpus page on wpdeploy confirmed the cause: real signal was being lost at the tokenizer stage.Tokenizer changes (
inc/stats/class-keyword-extractor.php)Three pre-passes now run before the standard split-on-non-alpha:
1. Hyphenated / x-separated calibers —
.45-70,.30-06,7.62x54r,8x57. Without this they're split into pure-digit fragments and dropped, losing the actual model identifier.2. Caliber-with-suffix —
9mm,.22lr,.45acp,.380acp. Previously only survived by accident because of the trailing letters; now extracted explicitly.3. 4-digit model years 1700–2099 —
1873,1903,1911,1971. Pure-digit tokens were unconditionally dropped; now retained when year-shaped.Standard pass relaxed to allow 4-digit pure-digit tokens between 1700 and 2099.
Stop-word additions (
inc/stats/stop-words.php)Conservative — only universally empty auction descriptors:
original,marked,accessories,decorative,household,goods,made,condition,assortmentDeliberately NOT added:
antique,vintage,rare,fine— those carry buyer-segmentation signal (antiquarian buyers vs. modern-collectibles buyers). Borderline cases (metal,wooden,american,model) are left to the wpdeploy-side IDF re-rank.Companion change on wpdeploy (no plugin update needed)
refresh_people_rollup.phpnow multiplies each keyword's score by an IDF factor pulled fromkeyword_idf(refreshed hourly byrefresh_lot_keyword_index.php). Generic keywords that appear in many lots get demoted automatically; brand/maker words that only appear on a handful get lifted into the top-5 chips.After deploying this version, reset the
auctionforge_lots_sync_watermarkoption on each site and clear thewp_af_stats_lot_keywordstable to force re-extraction of every lot through the new tokenizer.---
[3.7.0.10] — 2026-05-03
Lots sync — ship resolved CDN image URL, not bare BidSpirit filename
class-lots-sync.phpwas sendingimagesListStr's first comma-token verbatim asimage_url— that's the raw BidSpirit storage value (e.g.001.jpg). Wpdeploy received a bare filename, the browser resolved it against the wpdeploy host, and every lot thumbnail 404'd.The lots-sync now instantiates
LotImageand pulls the resolved CDN URL (LABEL_MEDIUMthumbnail), with fallback toLABEL_ORIGINALand a final defensive check that drops anything that doesn't start withhttp(s)://. Resolution is wrapped in try/catch — a missing class or BidSpirit settings issue leavesimage_urlempty rather than blowing up the sync batch.After deploying this version on a site, reset its
auctionforge_lots_sync_watermarkoption (delete the row) to re-push existing lots through the new resolver. The wpdeploy view skips<img>rendering whenimage_urlisn't a real URL, so dirty rows degrade silently while the watermark catches up.---
[3.7.0.9] — 2026-05-03
Keepalive sweep — auto-clears WP upgrader debris that produces silent "Could not create directory" failures
WordPress 6.x's atomic-rollback flow leaves
wp-content/upgrade-temp-backup/lying around when its post-install cleanup misfires (the user-facing symptom is "Update failed: Could not create directory" after an update that has actually already succeeded). Stalewp-content/upgrade/<plugin>-tmp/and.maintenancelockfiles from crashed upgrades cause the *next* upgrade attempt to fail the same way. None of WP's own scheduled cleanup catches these reliably.The keepalive mu-plugin (
KEEPALIVE_VERSION1.1.0) now sweeps all three classes of debris on every page load, transient-guarded to once per hour. Safety thresholds prevent it touching anything actually in flight:.maintenancefiles less than 5 min old,wp-content/upgrade/*entries less than 60 min old, andupgrade-temp-backup/less than 30 min old are left alone. Wrapped in try/catch with no throws, so the sweep can never block a request.The keepalive installer detects the version bump and rewrites
wp-content/mu-plugins/auctionforge-keepalive.phpautomatically on the next AF load, no manual reactivation needed.---
[3.7.0.8] — 2026-05-03
Shop auction UI refinements & share button settings
Shop (Buy-It-Now) catalog improvements
- Shop sorting dropdown: Added a dedicated sorting dropdown for shop catalogs with options: Recently Added, Price: High, and Price: Low. Sorts by
buyoutPricemetadata. Regular auction catalogs retain the original sorting options. - Removed "Buyout price:" label: On shop lot pages, the redundant "Buyout price:" text before the price is now hidden. Only the price and "Buy Now" button are displayed. Regular auction buyout lots still show the label.
- Removed increments table & terms links: On shop lot pages, the "Increments table" and "Terms and conditions" links are hidden since they don't apply to buy-it-now items. The "Make an inquiry" link remains.
Buyout confirmation modal overhaul
- Sales tax logic: The buyout confirmation modal now follows the same sales tax detection as the regular bid modal. When the auction house has a US state configured, displays "Sales Tax" instead of "VAT", with the correct percentage for same-state buyers and 0% for out-of-state.
- Hide 0% buyer's premium: The Buyer's Premium line is hidden when the commission is 0%.
- Shop-specific text: For shop buyouts, all disclaimer text is replaced with: *"You will receive an email with your invoice, including shipping, and a secure payment link."*
- Shop-specific buttons: "I don't Agree" → "Cancel", "I Agree" → "Buy". The "Terms of sale" button is removed for shop buyouts. Non-shop buyouts retain the original layout.
Purchase confirmed screen
- Title changed from "Confirm purchase:" to "Purchase Confirmed".
- Thank you message updated to: *"Thank you for your order. We will confirm your order within 1-2 business days and email you an invoice, including shipping, and a secure payment link."*
Share button settings (Appearance tab)
- Added a Share Buttons section to the BidSpirit Appearance settings tab with individual checkboxes for each sharing platform: Copy Link, WhatsApp, Facebook, Telegram, X (Twitter), VK, Pinterest, and Email.
- All platforms default to enabled (shown). Unchecking a platform hides that share button on all lot pages (both shop and regular auctions).
---
[3.7.0.7] — 2026-05-02
Identity stitch on bidder login — keyword interest tallying now actually fires
Why
The keyword extractor was filling
wp_af_stats_lot_keywordscorrectly (197 lots, 734 distinct keywords on Clumber), butwp_af_user_interestsandwp_af_user_recent_activitywere both empty — zero rows of any dimension. Same on every site running the new sync streams.Root cause: identity stitching (visitor_hash → email) only fired in the tracker AJAX when
is_user_logged_in()returned true. On these auction sites the actual bidders authenticate via BidSpirit, never aswp_users— so the WP login check was always false, the stitch table stayed empty, andmaybe_record_lot_view($url, $email, …)got called with an empty email and bailed out before tallying. Lot views by real bidders never landed in the user-side interest profile.What changed (no auth-path intervention)
The fix piggybacks on the *existing* fire-and-forget tracking AJAX that already runs after a successful BidSpirit login (
afLogIP("login", bidspiritUser)). It does not touch the BidSpirit auth path itself.inc/ip-logger.phpauctionforge_ajax_log_ip()— after the existingauctionforge_user_trackinginsert, if the request carries avisitor_hashand the email is valid, callsAF_Stats_Visitor_Email_Map::record($vh, $email, $ip). Wrapped in try/catch so any failure here can never break the existing tracking response.assets/js/app.js+src/js/app.jsafLogIP()— readslocalStorage['af_vid'](defensively, ITP/private-mode safe) and includes it asvisitor_hashin the POST body.inc/stats/class-stats-init.phpmaybe_record_lot_view()— when$emailis empty (the common case for BidSpirit-only bidders) but avisitor_hashis present, falls back toAF_Stats_Visitor_Email_Map::lookup($visitor_hash). If a stitch exists, the view tallies; if not, it stays anonymous.
Net effect: a bidder logs in (BidSpirit), the post-login tracker AJAX fires as it always has, and now also writes one extra row into
af_stats_visitor_emails. From that point onward, every page they view on the same browser/device tallies intoaf_user_interestskeyed on their email. The BidSpirit transaction itself is untouched.---
[3.7.0.6] — 2026-05-02
Critical fix —
X-API-Keyheader collision with sibling SmoothByte pluginsWhat was wrong
On any site running both AuctionForge and another SmoothByte-stack plugin that also points its updater at
wpdeploy.smoothbyteit.dev(e.g.seo-aeo-optimizer), the second plugin'shttp_request_argsfilter overwrote AuctionForge'sX-API-Keyheader on every outbound API call. Wpdeploy then 401'd because the key it received belonged to a different plugin instance — usually aseo_aeo_update_api_keythat wpdeploy had no record of.The symptom was a quiet, total auth failure:
report-health,check-updates, everysync-*route, all 401. The watchdog flagged streams as "gone" and updates stopped flowing. Affected sites: any install where the AuctionForge key and the sibling plugin's key happen to differ. Sites where both plugins shared a key were silently safe (the overwrite was a no-op).Fix
AuctionForge_Auto_Updater::add_download_auth()now refuses to clobber an existingX-API-Keyand, for download URLs, only stamps when the URL slug matches our own. That keeps targeted calls fromapi_request()intact regardless of filter ordering, and prevents either plugin from writing its key onto the other's download URL.The same fix has been applied to
seo-aeo-optimizerso both ends of the collision are defensive.---
[3.7.0.5] — 2026-05-02
Sync Status admin panel — diagnostic + manual triggers in wp-admin
Why
Diagnosing sync issues used to require shell access on the site or piecing together state from wpdeploy's app.log. This release surfaces the same diagnostics inside wp-admin so a site admin (or anyone with
manage_options) can see exactly what's happening and trigger fixes in one click.Lives inside the existing Sync Status menu (
Lots → Sync Status) — appended below the existing content as a "Sync Diagnostics & Manual Controls" section, no duplicate menu entry.What's on the panel
Connection summary — plugin version,
af_stats_db_version, wpdeploy server URL, last 8 chars of API key, keepalive install state + auto-reactivation count.Sync streams table — for each of the 10 cron hooks (user-tracking, user-profile, user-interests, user-activity, lots, bids+wins, vulnerabilities, report-health, check-updates, fraud-enforcement):
- Configured schedule
- Last fired timestamp + status colour-coded (green=success, blue=idle/empty, red=error)
- Record count from last run
- Next scheduled run
- Current watermark (where applicable)
- "Fire now" button — clears doing_cron, calls
do_action($hook)synchronously, shows the result
One-shot utilities
Test wpdeploy connection— calls/api.php/infowith the site's API keyClear stuck cron lock— deletes thedoing_crontransient (the classic fix when scheduled events stop firing)Reinstall keepalive— overwritesmu-plugins/auctionforge-keepalive.phpfrom the bundled templateBackfill bids from legacy tracking— replayslast_event_type='bid'rows fromwp_auctionforge_user_trackingintowp_af_bid_eventsso the bids-wins stream picks them up. Useful for sites that have years of bid history in the legacy table but nothing in the new queueRun all due events now— clears doing_cron and fires everyauctionforge_*cron event whose timestamp is past due, in one go
Live response output panel shows the JSON returned from each action so you can see what just happened without leaving the page.
Files Changed
- Created:
inc/admin/class-sync-status-page.php - Modified:
inc/stats/class-stats-init.php(load + init the panel) - Modified:
admin/view/sync-status.php(appendAF_Sync_Status_Page::render_panel()call at the bottom) - Modified:
auctionforge.php(Version 3.7.0.4 → 3.7.0.5)
Verification
Navigate to Lots → Sync Status in wp-admin on any 3.7.0.5 site. Scroll past the existing content to the new "Sync Diagnostics & Manual Controls" section. Click "Test wpdeploy connection" — you should see
{"success": true, "auth_type": "site"}. Click "Fire now" on any stream — the row's last-fired timestamp should refresh after 1–2 seconds.---
[3.7.0.4] — 2026-05-02
Self-healing: failed plugin updates can no longer take a site offline
Why
WordPress's plugin updater isn't transactional — when an update fails partway (corrupt unzip, fatal during the new version's
plugins_loaded, disk pressure, theme conflict, etc.) WP often deactivates the plugin and leaves the site without it. Once AuctionForge is dropped fromactive_plugins, no AF code runs again — including its sync handlers — until someone notices and reactivates manually. On the AuctionForge site fleet, this had quietly happened to ~5 sites we found; almost certainly more on production sites we don't have filesystem access to.This release ships an autonomous watchdog that lives outside the AuctionForge plugin entirely so it survives even when AF gets knocked out.
What changed
1. Self-installing keepalive (mu-plugin)
inc/keepalive/auctionforge-keepalive.template.php— a 50-line WordPress must-use plugin. Lives inwp-content/mu-plugins/, which WordPress can't deactivate. On everyplugins_loaded(priority 1, before any regular plugin), it checks: isauctionforge/auctionforge.phpon disk but missing fromactive_plugins? If yes AND the file has a validPlugin Name:header (smoke check — don't reactivate a corrupt zip), it re-adds AF andincludes the file in the same request.inc/keepalive/class-keepalive-installer.php— runs on every successful AF load. Copies the template intowp-content/mu-plugins/auctionforge-keepalive.phpif missing or version-bumped. Idempotent: comparesKEEPALIVE_VERSIONheaders, only writes on change. Refuses to overwrite a foreign mu-plugin (defensive against name collisions). Failure is non-fatal — install errors are recorded inwp_optionsfor wpdeploy visibility but never throw.
Net effect. Any site that successfully loads AF 3.7.0.4 or later will have the keepalive permanently installed in mu-plugins. From that point forward, even if a future update hard-fails, the keepalive recovers AF on the next pageview without any manual intervention or filesystem access. Crucially: this works on sites we don't own — the keepalive ships inside the AF zip, gets installed during the first successful update, and lives in mu-plugins thereafter.
2. Forensic markers
The keepalive writes three options on each recovery:
auctionforge_auto_reactivated_at— most recent recovery timestampauctionforge_auto_reactivated_count— total recoveriesauctionforge_auto_reactivated_failed_at— set when the keepalive saw AF on disk but with no Plugin Name header (genuinely corrupt — needs operator attention)
These get picked up by the AF sync streams and surfaced on the wpdeploy dashboard so you can see which sites have been quietly recovering themselves and whether a particular release is failing more than it should.
3. Companion: post-update-silence alerts on wpdeploy (server side)
Wpdeploy's
report-healthroute now compares incomingplugin_versionagainst the row and writeslast_version_changed_at+previous_plugin_versionon change. TheSyncWatchdogcron then alerts if a site has reported a version change but not sent any heartbeat for 2+ hours since — likely a failed install. Emitssync_incidentsrows withkind=post_update_failureso the existing Telegram fan-out picks them up. Each version-change event alerts at most once.Files Changed
- Created:
inc/keepalive/auctionforge-keepalive.template.php,inc/keepalive/class-keepalive-installer.php - Modified:
inc/stats/class-stats-init.php(callAF_Keepalive_Installer::maybe_install()on every plugin load) - Modified:
auctionforge.php(Version 3.7.0.3 → 3.7.0.4)
Companion server-side changes (already deployed on wpdeploy.smoothbyteit.dev — not in this zip):
sitestable:last_version_changed_at TIMESTAMP NULL,previous_plugin_version VARCHAR(20) NULLapi.php/report-health route detects version changesSyncWatchdog::maybe_alert_post_update_failure()emits the new alert kind
Verification
1. Drop a 3.7.0.4 install on any site. Confirm
wp-content/mu-plugins/auctionforge-keepalive.phpexists post-load.2. Manually deactivate AF from the database (
DELETE FROM wp_options ...active_plugins...). Hit the homepage. AF reappears inactive_plugins;auctionforge_auto_reactivated_countincrements.3. Delete
mu-plugins/auctionforge-keepalive.php. Trigger AF load (any pageview). The file reappears.4. Bump KEEPALIVE_VERSION in the source template, ship a new release, observe the installed mu-plugin update on next AF load.
Operator notes
- Sites currently in the broken state (AF deactivated, no keepalive yet) are NOT auto-rescued by this release — they need a one-time manual reactivation in wp-admin OR a fresh AF install via wp-admin's Upload Plugin. After that, the keepalive is in place and future failures self-heal.
- The post-update-failure alert won't fire for upgrades that happened before this release (no
last_version_changed_atwas recorded). It activates from the first version change wpdeploy sees from each site after this update lands.
---
[3.7.0.3] — 2026-05-02
Fix: profile re-sync on login / profile-edit / register (no more empty names)
Why
The hourly profile sync uses a
user_registeredwatermark — once a user has been pushed once, the watermark advances past them and they're never re-pulled. That meant:1. Existing users whose first_name/last_name became populated AFTER their first sync stayed empty on wpdeploy forever.
2. BidSpirit-driven sites that don't write WP's standard
first_name/last_namefields shipped empty rows even though the canonical name was visible indisplay_name.The People view was showing
—for the name on rows that absolutely had a name available — just not where the sync handler was looking.Fixes (
inc/sync/class-profile-sync.php+inc/stats/class-stats-init.php)AF_Profile_Sync::push_for_user_id($user_id, $blocking=false)— new public method that builds a single user's profile row, normalises it, and POSTs to wpdeploy bypassing the watermark. Non-blocking by default (wp_remote_postwithblocking=false, timeout=2s) so login latency is unaffected.build_user_row($user_id)extracted as a reusable helper. Both the hourly batch and the on-demand push call it. Centralises role-filtering + display_name fallback + usermeta probing.display_namefallback. Whenwp_usermeta.first_name/last_nameare both empty (typical on BidSpirit-only sites),build_user_row()parsesdisplay_name("John Smith" → first=John, last=Smith) so we don't ship a row with a blank name when the data is sitting on the user record itself.- Three new action hooks registered in
class-stats-init.php::init(): wp_login→push_for_user_id($user->ID)— every login refreshes the rowprofile_update→ same — profile edits in wp-admin refreshuser_register→ same — new registrations get pushed instantly (instead of waiting up to 60 min for the next cron tick)
Files Changed
- Modified:
inc/sync/class-profile-sync.php(refactor + new method + display_name fallback) - Modified:
inc/stats/class-stats-init.php(three new action hooks) - Modified:
auctionforge.php(Version 3.7.0.2 → 3.7.0.3)
Verification
1. On a 3.7.0.3 site, find a user whose
wpdeploy.user_profiles.first_nameis empty:SELECT site_id, email, first_name FROM user_profiles WHERE email='something@example.com'2. Log in as that user (or have them log in).
3. Within ~2 seconds, re-query —
first_nameshould now be populated, either from the standard meta key OR parsed fromdisplay_name.4. The non-blocking POST means the user's login experience is unchanged — no spinner, no extra latency.
Operator note
Existing wpdeploy rows with empty
first_name/last_namewill refresh automatically as users log in or edit their profile. To force a one-shot re-walk of every user on a site (regardless of watermark), reset the watermark there:DELETE FROM wp_options WHERE option_name='auctionforge_profile_sync_watermark';Next hourly cron will re-pull every non-admin user with the new fallback applied.
---
[3.7.0.2] — 2026-05-02
Fix: sync-lots datetime mismatch + idle syncs now heartbeat
Why
Two issues surfaced in the wpdeploy Sync Health dashboard:
1. Every site's
sync-lotswas stuck onapi_error. The plugin sendslast_modifiedstraight fromwp_bp_meta_data.lastUpdate, which is a Unix epoch string ("1756919754"). wpdeploy'slots.last_modifiedcolumn is aDATETIME, so MariaDB rejects the insert withSQLSTATE[22007]: Incorrect datetime value. The handler recordsapi_errorand the watermark never advances, so every cron tick re-fails on the same batch.2. Sites with nothing to sync looked dead. When a sync handler had an empty batch (e.g. no non-admin users yet) it was returning early without POSTing anything. wpdeploy's
update_sync_health()only fires on a successful POST, sosites.sync_health_jsonstayed NULL and the dashboard showed grey dots — indistinguishable from a broken cron. WP-Cron was actually firing fine; the watchdog just couldn't tell.Fixes
inc/sync/class-lots-sync.php— newepoch_to_datetime()helper converts the BidSpirit epoch field to UTCY-m-d H:i:sbefore shipping. Idempotent: already-formatted datetimes pass through untouched, invalid values becomeNULL.inc/sync/class-sync-base.php::run()— always POST, even when the batch is empty. Empty payload is{records: []}and wpdeploy's existing handlers handle it gracefully (loop is skipped,update_sync_health()still fires withsynced=0). This makes the dashboard reflect cron liveness, not just data flow.
Files Changed
- Modified:
inc/sync/class-lots-sync.php - Modified:
inc/sync/class-sync-base.php - Modified:
auctionforge.php(Version 3.7.0.1 → 3.7.0.2)
Verification
1. On Clumber:
do_action('auctionforge_sync_lots')— confirm the previousauctionforge_last_sync-lots_status = api_errorflips tosuccess(N)and thatwpdeploy.lotsnow contains rows.2. On a site with no non-admin users:
do_action('auctionforge_sync_user_profile')— confirmauctionforge_last_sync-user-profile_status = idle(0)AND that wpdeploy's Sync Health page now shows a green dot for that cell.---
[3.7.0.1] — 2026-05-02
Fix: marketing data leaks WordPress admins into the people list
Why
After the 3.7.0.0 rollout the central
peopleview on wpdeploy was showing site administrators alongside real auction-house users — thesync-user-profilehandler read straight fromwp_userswith no role filter, so any account with administrator/editor/author/contributor/shop_manager capabilities was getting shipped as if it were a buyer. Marketing audiences must contain buyers, not staff.Fixes (
inc/sync/class-profile-sync.php)- The
read_batch()SQL now LEFT JOINs{$wpdb->usermeta}on the prefix-aware capabilities key ({$wpdb->prefix}capabilities) and filters out any user whose serialized capabilities meta_value containsadministrator,editor,author,contributor,shop_manager, orsuper_admin. Users withIS NULL(no roles registered) are still allowed through — those are typically subscribers/buyers on this fleet. - Watermark on
auctionforge_profile_sync_watermarkis unchanged; the next run after upgrade picks up the same batch with the new filter applied. Operationally the wpdeploy team also wiped the existing admin rows fromuser_profiles,user_interests,user_recent_activity,bids_wins, andpeopleto clear the leak server-side — total of 35 rows scrubbed.
Files Changed
- Modified:
inc/sync/class-profile-sync.php - Modified:
auctionforge.php(Version 3.7.0.0 → 3.7.0.1)
Verification on Clumber dev
1. Find a logged-in admin:
SELECT u.user_email FROM wp_users u JOIN wp_usermeta um ON um.user_id=u.ID AND um.meta_key='wp_capabilities' WHERE um.meta_value LIKE '%administrator%';2. Reset the watermark:
DELETE FROM wp_options WHERE option_name='auctionforge_profile_sync_watermark';3. Trigger sync:
do_action('auctionforge_sync_user_profile');4. On wpdeploy: confirm those admin emails do NOT appear in
user_profiles(SELECT * FROM user_profiles WHERE email='admin@…';returns zero rows).Privacy / scope
- No API contract changes. The wpdeploy
/api.php/sync-user-profileroute accepts the same payload shape; this is purely a source-side filter narrowing what gets sent.
---
[3.7.0.0] — 2026-05-02
Cross-site user data lake — full Phase 2 + Phase 3 build
Why
AuctionForge sites were exposing per-lot engagement (views, favourites, bids, wins) keyed only on the anonymous
af_vidlocalStorage hash, with no central aggregation. Marketing — even the "collect data now, send later" phase — needs a per-person view across the whole AF network: name + phone + postcode + country + IP + device fingerprint + the keywords they engage with + the bids they place + the lots they win, all rolled up across every site they've used. This release wires every piece needed for that, and keeps it sustainable: per-site aggregates rather than raw event firehose, watermarked syncs with retry, 14/30-day site-side retention, watchdog + Telegram alerts for dead streams.See
/root/.claude/plans/i-want-to-add-synthetic-goose.mdfor the full architecture.New tables (idempotent dbDelta on the existing
plugins_loadedmigration path)wp_af_stats_lot_keywords— per-lot keyword cache. Title + tags + author tokenized (lowercase → drop stop-words → drop ≤2-char → drop pure-digit), one row per (post_id, keyword). Populated onsave_post_lot.wp_af_user_interests— running tally per(user_email, dimension, dimension_value)where dimension ∈keyword | category | author | price_band. UPSERT-keyed so increments are atomic. Bounded by users × distinct interests (typically a few dozen rows per user).wp_af_user_recent_activity— capped per-user activity log (last 50 events per email). Seeds the drill-down timeline on the wpdeploy person view.wp_af_bid_events— bid + win events (auto-created by the bids sync handler). Drained and shipped to wpdeploy hourly.synced_atcolumns added towp_af_stats_pageviews,wp_af_stats_sessions,wp_af_stats_searches,wp_af_stats_outbound. Powers the durable sync-and-purge lifecycle.af_stats_db_versionbumped 2 → 3. The existingAF_Stats_Init::maybe_create_tables()picks up the new tables on the next admin page load after auto-update.
New helper classes
AF_Keyword_Extractor(inc/stats/class-keyword-extractor.php) — pure tokenizer + cache writer + read-through helper. Hookssave_post_lotto refresh on lot changes. Stop-words tunable viaapply_filters('af_keyword_stop_words', ...).AF_User_Interests(inc/stats/class-user-interests.php) —record_view / record_favorite / record_bid / record_win. All idempotent UPSERTs. CallsAF_Stats_Tracker::should_skip()first so admins/bots never pollute interest profiles.AF_Sync_Base(inc/sync/class-sync-base.php) — abstract durability backbone. Readssynced_at IS NULLbatches, POSTs, marks rows synced only on a confirmed 200, retries on next cron run if the POST fails. Idempotent UNIQUE keys on the wpdeploy side mean retries never duplicate.AF_Profile_Sync/AF_Interests_Sync/AF_Activity_Sync/AF_Lots_Sync/AF_Bids_Sync— five concrete sync streams.AF_Data_Purge(inc/maintenance/class-data-purge.php) — daily cron: 14-day floor on synced rows, 30-day hard cap with CRITICAL alert if any unsynced row hits the cap (which would mean wpdeploy has been unreachable for a month).
New cron schedules (auto-registered on plugins_loaded if
auctionforge_update_server_url+_api_keyare configured)| Hook | Schedule | Endpoint |
|---|---|---|
|
auctionforge_sync_user_profile| hourly |POST /api.php/sync-user-profile||
auctionforge_sync_user_interests| hourly |POST /api.php/sync-user-interests||
auctionforge_sync_user_activity| hourly |POST /api.php/sync-user-activity||
auctionforge_sync_lots| every 10 min |POST /api.php/sync-lots||
auctionforge_sync_bids_wins| hourly |POST /api.php/sync-bids-wins||
auctionforge_purge_synced_data| daily | (purge cron — local) |All sync handlers are watermarked or
synced_at-gated; cron mid-run failure is harmless because the next run picks up the same rows.Hooks fired
af_stats_pageview_recorded($url, $email, $visitor_hash)— fires insideAF_Stats_Ajax::handle_track()after a logged-in pageview is recorded. Default listener resolves URL → lot post →AF_User_Interests::record_view().af_stats_lot_favorited($email, $post_id)— fires from the existinglot_analytics_record_favoriteAJAX handler when a watchlist add happens. Default listener callsrecord_favorite().
Server-side companion (wpdeploy)
This release is paired with wpdeploy changes (handled out-of-band; not in the plugin zip):
- 5 new API routes matching the sync streams above. All return
synced+ watermark metadata so the plugin can advance / mark rows synced. update_sync_health()helper in wpdeploy — every successful sync POST writes(stream, last_seen_at, last_synced_count, state)intosites.sync_health_json.SyncWatchdog— 5-minute cron on wpdeploy that scans every (site × stream) cell and runs anok → overdue → gone → recovering → okstate machine. Emits alerts via the existingsync_incidentsTelegram fan-out.- People section in the wpdeploy admin —
?tab=people(cross-site rollup with top keywords / lifetime spend),?tab=person&email=...(drill-down with timeline + bids),?tab=people-export(Google Customer Match + Meta Custom Audience CSV with sha256 hashing per spec). ?tab=sync-health— site × stream traffic-light grid showing every sync's state.
Files Changed
- Created:
inc/stats/class-keyword-extractor.php,inc/stats/class-user-interests.php,inc/stats/stop-words.php - Created:
inc/sync/class-sync-base.php,inc/sync/class-profile-sync.php,inc/sync/class-interests-sync.php,inc/sync/class-activity-sync.php,inc/sync/class-lots-sync.php,inc/sync/class-bids-sync.php - Created:
inc/maintenance/class-data-purge.php - Modified:
inc/stats/class-stats-database.php(DB_VERSION = 3, new dbDelta calls, synced_at column adds) - Modified:
inc/stats/class-stats-init.php(require new classes, register sync crons, wireaf_stats_pageview_recordedandaf_stats_lot_favoritedlisteners) - Modified:
inc/stats/class-stats-ajax.php(fireaf_stats_pageview_recordedafter pageview record; fireaf_stats_lot_favoritedon watchlist add) - Modified:
auctionforge.php(Version: 3.6.4.0 → 3.7.0.0)
Verification on Clumber dev
1. After auto-update + first wp-admin page load:
wp_af_stats_lot_keywords,wp_af_user_interests,wp_af_user_recent_activityall exist;af_stats_db_version = 3.2. Save a test lot titled
"Pair of Victorian silver candlesticks by Mappin & Webb"→wp_af_stats_lot_keywordshas rows forvictorian, silver, candlesticks, mappin, webb(and notpair, of, by).3. Log in as throwaway test user, view 3 of those lots →
wp_af_user_interestsshows(test@…, keyword, 'victorian', view_count=3).4. Wait one hourly cron, confirm
wpdeploy.user_interestsmirror via the wpdeploy admin →?tab=people→ search for the test email.5. Confirm
wpdeploy.sites.sync_health_jsonhasuser-interests.state = 'ok'for the Clumber site.6. Pause the cron, wait 2h, watch the watchdog flip the cell to
overdueand emit a Telegram alert.Privacy / scope
- Admins and bots are filtered out at write time via
AF_Stats_Tracker::should_skip(). - Email is normalized lowercase + trim before storage; phone normalized to E.164 (UK-aware) on the sync side.
- No outbound activation yet — wpdeploy stores everything but doesn't send anything to anyone. Marketing send mechanics (consent flag, suppression list, sender) explicitly deferred.
---
[3.6.4.0] — 2026-05-02
Identity stitching: visitor_hash → user_email
Why
The
af_stats_*tables (pageviews,sessions,searches,outbound) and the lot-engagement tables (af_lot_analytics,af_lot_shares) currently store activity keyed only on the anonymousaf_vidlocalStorage hash — there is no link from any browsing event to the user's email even when they're logged in. Without that link, the central wpdeploy server can never aggregate behavioural data on a per-person basis, which is the prerequisite for the cross-site user-data lake being built on wpdeploy (see/root/.claude/plans/i-want-to-add-synthetic-goose.mdPhase 1).This release adds the bridge: every authenticated tracker hit records a
(visitor_hash, user_email)pair into a new table. From here on, anonymous browsing can be resolved to an email via JOIN for any session the user was logged in.Changes
- New table
wp_af_stats_visitor_emails—(visitor_hash, user_email, ip_address, first_seen, last_seen)withUNIQUE(visitor_hash, user_email)+ index onuser_email. Created viadbDeltainside the existingAF_Stats_Database::create_tables()so it ships through the standardplugins_loadedmigration path — no manual reactivation needed after auto-update. af_stats_db_versionbumped 1 → 2.AF_Stats_Init::maybe_create_tables()now compares against the newAF_Stats_Database::DB_VERSIONconstant rather than a hard-coded< 1, so future schema bumps (Phase 2 onwards) just require constant edits + new dbDelta calls.- Identity record on every authenticated tracker hit.
AF_Stats_Ajax::handle_track()now callsAF_Stats_Visitor_Email_Map::record($visitor_hash, $email, $ip)wheneveris_user_logged_in()is true. Trust boundary: the email is read server-side fromwp_get_current_user()— clients cannot assert who they are. - Defensive table-exists guard. The new helper short-circuits silently if the migration hasn't run yet on a given site (race window on the very first request after auto-update); the next request finds the table and proceeds. No fatals, no missing rows.
- Email normalised at write time — lowercase + trim +
is_email()validation before storage. Marketing audience match-rates downstream depend on consistent casing.
Files Changed
- Created:
inc/stats/class-visitor-email-map.php - Modified:
inc/stats/class-stats-database.php(DB_VERSION constant; new table; drop_tables list) - Modified:
inc/stats/class-stats-init.php(require new helper; migration check uses constant) - Modified:
inc/stats/class-stats-ajax.php(record pair inhandle_track) - Modified:
auctionforge.php(Version header bump)
Verification on Clumber dev
1. After auto-update, load any
wp-admin/*page once →wp_af_stats_visitor_emailsexists,af_stats_db_version = 2.2. Log in as a test user, browse 5 lots → exactly one row in
wp_af_stats_visitor_emailsfor that(visitor_hash, email)pair, withlast_seenupdating on each hit.3.
SELECT email FROM wp_af_stats_visitor_emails WHERE visitor_hash IN (SELECT visitor_hash FROM wp_af_stats_pageviews WHERE created_at > NOW() - INTERVAL 1 HOUR)returns the test email — proving the JOIN works.Privacy / scope
- This change writes a
(visitor_hash, email)pair to a single new table on the AF site. Nothing is sent to wpdeploy yet — the sync stream lands in Phase 2. - Anonymous (logged-out) browsing is unaffected: no row is created until the user authenticates.
- Bots are still skipped via
AF_Stats_Tracker::is_bot()before any tracking writes.
---
[3.6.3.1] — 2026-05-01
Fix: New lots never processed + Live console improvements
Why
When BidSpirit adds new lots to an auction (e.g. items 683-692), the sync pipeline correctly staged all 709 lots into
import_historybut the InsertLotsBS processing loop exited after the first batch of 500 unchanged lots, never reaching the genuinely new lots at the tail of the queue. This caused new lots to remain permanently stuck in staging — synced but never created as WordPress posts.Separately, the admin Live Console was replaying the entire log history from the beginning on every page load, and showed long silent gaps during API calls with no indication of what the worker was doing.
Fixes
- InsertLotsBS loop break condition — The stage 5 insert loop in
CatalogSyncWorker::process()andprocessDayEnded()previously broke whenupdated lots === 0, even if the batch had cleared hundreds of unchanged ("unupdated") lots from the queue. New lots with higher IDs were never reached. Now breaks only when bothupdated lotsandunupdated lotsare 0, meaning the staging queue is truly empty. - Live Console starts from current position —
consoleSinceIdwas hardcoded to0, causing the console to page through the entireaf_sync_logtable (50 rows at a time) before reaching real-time entries. Now initializes toSyncLogger::getLatestId()so only entries created after page load appear. queueIsActivedeclaration order — Variable was declared after functions that referenced it, causing the console to always start at the slow 3s polling rate even when a worker was active. Moved declaration before first use.- Progress logging during API calls —
LotList::auctionProcessing()made 2-3 BidSpirit API calls with zeroSyncLoggerentries, creating long silent gaps in the console. Added log entries for API fetch start, response received (with duration), data staged, and API errors. - Per-auction progress in bulk runs —
LotList::run()now logsProcessing auction X/Y: {id}for each auction in the bulk loop, and logs skipped auctions. processDayEndedinsert loop logging — Added batch progress logging and timeout guard matching theprocess()method pattern. Previously this loop was completely silent.
Files Changed
- Modified:
inc/sync/CatalogSyncWorker.php,inc/import/LotList.php,admin/view/sync-status.php
---
[3.6.3.0] — 2026-05-01
Public Auctions API — Token Authentication
Why
The
/wp-json/auctionforge/v1/public/auctionsendpoint added in v3.6.2.9 was publicly accessible. Since auction data should only be served to authorized aggregator sites, the endpoint now requires a valid auth token.Changes
- Token verification — The
PublicAuctionsREST endpoint now validates anX-AF-Tokenheader (or?token=query parameter) against the site's existing Webhook auth token from AuctionForge settings. - Returns
401 Unauthorizedfor missing/invalid tokens and403 Forbiddenif no auth token is configured on the site. - Uses
hash_equals()for timing-safe comparison.
Files Changed
- Modified:
auctionforge.php,inc/api/PublicAuctions.php
---
[3.6.2.9] — 2026-05-01
Public Auctions REST API Endpoint
Features
- New REST endpoint
GET /wp-json/auctionforge/v1/public/auctions— Exposes auction list data (title, date, image, state, catalog link) for consumption by the AuctionForge Hub plugin on parent/main sites. - Parameters:
type(upcoming or past, default: upcoming),limit(max results, default: 50). - Handles multi-day auctions with correct part numbers and catalog links.
- Returns auction metadata including
auction_id,source_site, andday_indexfor deduplication.
Files Changed
- Modified:
auctionforge.php,inc/coreIncludes.php - Created:
inc/api/PublicAuctions.php
---
[3.6.2.8] — 2026-04-30
Suppress alerts for transient retry conditions
Why
The "BidSpirit API returned 0 lots — catalog may not be ready yet" message is logged when the BidSpirit webhook fires before the auction catalog is fully published. The safety cron retries the job automatically and it usually succeeds on the next attempt — there's no operator action required, so a Telegram alert is just noise.
Fix
- New private helper
SyncLogger::isSuppressedFromAlerts($message, $context)matches the message against a substring allowlist of known-transient errors. When matched, the row is still inserted intoaf_sync_log(so the in-app sync console still shows the retry chain) but theauctionforge_sync_error_loggedfan-out action does NOT fire — wpdeploy and Telegram stay quiet. - Default suppression substrings:
"BidSpirit API returned 0 lots","catalog may not be ready yet". - Extendable via the new
auctionforge_sync_alert_suppress_patternsfilter — themes/MU plugins can add their own substrings.
Files Changed
- Modified:
auctionforge.php,inc/sync/SyncLogger.php
---
[3.6.2.7] — 2026-04-30
Typo fix
- Settings → Connections tab: the placeholder/help text under the Server field showed
https://my-accaunt.bidspirit.com/(extra "a"). Now readshttps://my-account.bidspirit.com/.
Files Changed
- Modified:
auctionforge.php,inc/controllers/Settings.php
---
[3.6.2.6] — 2026-04-30
Fix stale
plugin_versionin reportsWhy
Sites were reporting their old version to wpdeploy long after they'd been upgraded — e.g. Lonsdale Auctioneers ran v3.6.1.1 but kept telling wpdeploy it was on v2.9.6. Root cause: the constant
AUCTIONFORGE_VERSIONis read from the plugin file'sVersion:header *once at plugin load*, then frozen into$this->current_versionon the auto-updater instance. After a plugin upgrade replaces the file on disk, existing PHP-FPM workers keep using the cached constant value until they're recycled, so every report from those workers carries the old version.Fix
- New helper
AuctionForge_Auto_Updater::get_live_version()reads the version directly from the plugin file's header on each call (viaget_file_data()— uncached). report_health,push_sync_error_immediate, andretry_sync_errorsnow sendget_live_version()instead of the cached constant.- The pre-existing iteration through active plugins inside
report_healthalready usedget_plugin_data()per plugin, so secondary plugin entries were already accurate; only the top-levelplugin_versionfield was stale.
Files Changed
- Modified:
auctionforge.php,inc/class-auto-updater.php
---
[3.6.2.5] — 2026-04-30
Real diagnostics for plugin self-updates
Why
The wpdeploy
update_queuetable had a 46% historical failure rate, but every single failure row stored the literal string"Installation failed"— collapsing every failure mode into one opaque error with no diagnostic value. Root cause: theinstall_update()method in both clients (AF auto-updater and wpd-client) treatedPlugin_Upgrader::upgrade()as a boolean, throwing awayWP_Errorobjects and skin-emitted error messages.Fixes (
inc/class-auto-updater.phpinstall_update())- Refreshes the
update_pluginstransient before invoking the upgrader. The upgrader reads from this transient to know what version to download; if WP hasn't checked recently, the upgrader silently returns false (looking like a failure even though there's a real update queued at wpdeploy). - Distinguishes
WP_Error,false/null, and success.WP_Errorwas previously treated as truthy → reported as "completed" even on failure. Now extracts the error code and message. - Reads
Automatic_Upgrader_Skin::get_errors()to surface the real upgrader-emitted error messages. - Reads
$upgrader->resultwhich holds the finalWP_Errorfor some failure paths. - Captures PHP errors/warnings emitted during the upgrade (file-move issues, etc.) via a temporary
set_error_handler. - Detects "no update in transient" as a distinct failure cause and labels it explicitly so we know it's a transient-cache problem, not an actual install failure.
- Truncates the combined diagnostic to 1000 chars before sending.
The same fix is applied to
wpd-client.php(the WPD client plugin shipped fromclient-plugin/wpd-client.phpon the wpdeploy server).Files Changed
- Modified:
auctionforge.php,inc/class-auto-updater.php
---
[3.6.2.4] — 2026-04-30
Bulk-sync worker dispatch fix
Fixes
- The HTTP-loopback worker (
auctionforge_rest_sync_workerinauctionforge.php) had its own switch statement for job-type dispatch, distinct from the one incrontasks/syncWorker.php. The newfull_sync_upcomingandfull_sync_pastjob types were only added to the CLI worker, so the loopback path produced "Unknown job type" errors. Both switches now route those types toBulkSyncWorker::process. inc/coreIncludes.phpnowrequire_oncesBulkSyncWorker.phpso the class is available wherever sync code runs.
Files Changed
- Modified:
auctionforge.php,inc/coreIncludes.php
---
[3.6.2.3] — 2026-04-30
Fixes for end-to-end Telegram round-trip
Fixes
verify_api_keyreads the option fresh on every call (hash_equalsagainstget_option('auctionforge_update_api_key')) instead of relying on the cached$this->api_keyfrom constructor time. Different FPM workers can hold different cached values when the option drifts (e.g. via auto-heal collisions), which previously produced intermittent 401s on REST endpoints.- New REST endpoint
POST /wp-json/auctionforge/v1/sync/version— wraps the existingtrigger-installflow with a JSON response (always HTTP 200 withsuccessflag). The original endpoint returnedWP_Error('no_update', …, status: 404)when the plugin was already on the latest version, which nginx'serror_page 404directive then clobbered with a static HTML 404 page on hosts using aaPanel/BTWAF. Keeping the URL under/sync/*matches the pattern that's already proven to pass through host WAFs.
Files Changed
- Modified:
auctionforge.php,inc/class-auto-updater.php
---
[3.6.2.2] — 2026-04-29
Catalog-sync kind disambiguation
Fix
catalog_syncjobs target a single auction that may be either active or archived. Until now their alerts were always classified askind=upcoming. The classifier now resolves the auction'sauction_stateterm meta and routes:ARCHIVED/ENDED/POST_AUCTION→kind=past→ Kill + Full Past buttons- anything else (or unresolvable) →
kind=upcoming→ Kill + Full Upcoming buttons
Files Changed
- Modified:
auctionforge.php,inc/class-auto-updater.php
---
[3.6.2.1] — 2026-04-29
Telegram Sync Monitoring follow-ups
Features
- Context-aware alert buttons. Each Telegram alert now shows the action set most relevant to the failing sync: upcoming-sync errors get Kill + Full Upcoming, past-sync errors get Kill + Full Past, everything else gets Kill only. Button choice is driven by a new
kindfield classified at log-write time from the queue'sjob_type. - Plugin version in alerts + Update button. Each push now includes the live
plugin_version. wpdeploy compares it to the latestis_stable=1row in itsversionstable and only renders an Update plugin button when the site is behind. Tapping Update calls the existingPOST /wp-json/auctionforge/v1/trigger-installendpoint to force the upgrade.
Architecture
- New private helper
AuctionForge_Auto_Updater::classify_error_kind($jobId)looks up the job'sjob_typeand maps it to'upcoming'/'past'/'other'. Used by both the immediate push and the 1-min retry cron. - Outbound payloads now include
plugin_versionat the top level; wpdeploy refreshessites.plugin_versionon every/sync-errorsPOST.
Files Changed
- Modified:
auctionforge.php,inc/class-auto-updater.php
---
[3.6.2.0] — 2026-04-29
Telegram Sync Monitoring & Remote Control
Features
- Instant Telegram alerts on sync errors. Any
level='error'row written toaf_sync_logis pushed (fire-and-forget, non-blocking) to wpdeploy, which fans it out to a configured Telegram group with inline-keyboard action buttons (Kill / Full Upcoming / Full Past / Acknowledge). - Remote command surface. Any group admin can tap a button to:
- Kill sync — flips DB flags via
SyncQueue::cancelAll(), then SIGTERMs every active worker; a 5-second watchdog escalates to SIGKILL for any survivor. - Full sync upcoming — full re-import of every active auction and its lots (queued, observable, killable). Replaces the
re-sync?do=importBidSpiritUpcomingflow with a queued equivalent. - Full sync past — same, for archived auctions.
- Safety-net retry cron (
auctionforge_retry_sync_errors, every minute) re-pushes recent error rows. wpdeploy dedupes viaUNIQUE(site_id, af_log_id)so duplicates are silent.
Architecture
SyncLogger::log()now firesdo_action('auctionforge_sync_error_logged', …)onlevel='error'so any handler can react. The auto-updater listener does a 2 s non-blocking POST to/api.php/sync-errors.- New REST endpoint
POST /wp-json/auctionforge/v1/sync/cancel-all(X-API-Key auth) — runsSyncQueue::cancelAll()+ SIGTERM + watchdog. Logs every action throughSyncLogger. POST /sync/startextended with amodeparameter (upcomingdefault,pastfor archived). Bulk re-sync is now a queued job, not a synchronous block.- New job types
full_sync_upcomingandfull_sync_pastonSyncQueue, dispatched to a newBulkSyncWorkerthat wraps the existingAuctionList::init()+LotList::init($upcoming)pipeline. syncWorker.phpinstalls a SIGTERM handler that flips the in-flight job tofailedwith a "Killed by admin (SIGTERM, cleanup OK)" marker and closes the DB cleanly before exiting. Watchdog escalates to SIGKILL after 5 s grace.LotList::auctionProcessing()now heartbeats the active bulk-sync job between auctions, preventing the safety cron from auto-failing long bulk runs as stale (the 600 s threshold is unchanged).
Files Changed
- Modified:
auctionforge.php,inc/sync/SyncLogger.php,inc/sync/SyncQueue.php,inc/class-auto-updater.php,crontasks/syncWorker.php,inc/import/LotList.php - Created:
inc/sync/BulkSyncWorker.php
---
[3.6.1.6] — 2026-04-29
High-Value Lot Modes for
[bp_lot_list]Features
high_value_pastmode — Displays past auction lots ordered by their catalog estimate (estimatedPriceInt), highest first. Useful for "Top Lots" or "Highlights" sections.high_value_soldmode — Displays past sold lots ordered by their actual sold price (soldBid), highest first. Only includes genuinely sold lots (soldBid > 0) and reuses the same false-positive guard asrandom_pastto skip lots wheresoldBidwas carried over fromstartPricewithout real bidding activity.- Admin documentation updated — The Shortcodes reference page in WP Admin now lists both new modes in the
modeattribute description and includes example shortcode usage.
Architecture
- New constants
MODE_HIGH_VALUE_PASTandMODE_HIGH_VALUE_SOLDonLotsWidget. - New method
LotsWidget::getLotListHighValue($mode, $limit)builds the query, applies the past-auction tax filter, setsbp_orderbyto the relevant meta field withDESCorder, and (for the sold variant) filters out unsold-but-stale lots in PHP. - New filter hook
bp_lot_list_high_value_args_filterfor downstream customization of the WP_Query args.
Files Changed
- Modified:
inc/widgets/LotsWidget.php,inc/controllers/ShortcodesPage.php
---
[3.6.0.18] — 2026-04-25
Brevo SMS Notifications Integration
Features
- Transactional SMS via Brevo API — The plugin now sends text message alerts through the Brevo transactional SMS service, running alongside existing Firebase push notifications.
- Four Notification Types:
- New Auction Published — Broadcast SMS to all opted-in subscribers when an auction is published.
- Auction Starting Soon — Targeted SMS to users registered for an auction when it is about to start.
- Favorited Item Live Soon — Targeted SMS to users who favorited a lot when it is approaching in the auction.
- Outbid Notice — SMS sent when a user's leading bid is surpassed, with a 5-minute per-item cooldown to prevent spam.
- SMS Subscriber Database — New
af_sms_subscriberstable stores user phone numbers, country codes, and per-notification-type opt-in preferences (GDPR-ready explicit consent). - Admin Settings Tab — New "SMS Notifications" tab in Settings with:
- Brevo API Key input
- SMS Sender Name (11 char max)
- Master enable/disable toggle
- Per-notification-type on/off switches
- Test SMS widget with phone input and send button
- Live subscriber count display
- Profile SMS Preferences — Users can opt into SMS notifications directly from their profile page with phone number entry and granular notification type selection.
Architecture
- BrevoSMS Service (
inc/services/BrevoSMS.php) — cURL-based API wrapper with broadcast, targeted, and single-send methods, message builders with 160-char limit awareness, rate limiting, and comprehensive error logging. - SMSSubscriber Model (
inc/model/SMSSubscriber.php) — CRUD operations, email-to-phone resolution, opt-in filtering, and upsert logic. - Webhook Integration — SMS dispatch hooks added to
AuctionsAPI.phpmethods:leading_bid_surpassed(),item_live_soon(),auction_starts_soon(), andauctionPublishedPush().
AJAX Handlers
auctionforge_sms_save— Save SMS preferences from profile pageauctionforge_sms_load— Load SMS preferences for profile pageauctionforge_sms_test— Admin-only test SMS endpoint
Database
- New table:
af_sms_subscribers— Phone numbers, country codes, per-notification opt-ins, timestamps
Files Changed
- Modified:
auctionforge.php,inc/coreIncludes.php,inc/controllers/AuctionsAPI.php,inc/controllers/Settings.php,admin/view/settings.php,templates/parts/profile-templates.php - Created:
inc/services/BrevoSMS.php,inc/model/SMSSubscriber.php
---
[3.6.0.7] — 2026-04-14
Hotfix
Fixes
- Namespace resolution — Fixed fatal error in
wp_footercommission label hook caused by unqualifiedSettingsHelperandSettingsclass references. Now uses fully qualified namespaces.
Files Changed
- Modified:
auctionforge.php
---
[3.6.0.6] — 2026-04-14
Commission Label Override Fix
Fixes
- Theme template override compatibility — Moved the commission label JS override from the
single-lot.phptemplate intoauctionforge.phpviawp_footerhook (priority 99). Sites with theme-level template overrides (e.g.themes/*/auctionforge/single-lot.php) were not picking up the inline script. Thewp_footerapproach works universally on all single lot pages.
Files Changed
- Modified:
auctionforge.php,templates/single-lot.php
---
[3.6.0.5] — 2026-04-14
Commission Label Override
Features
- Commission Label Setting — New dropdown in Settings → Appearance allowing admins to choose between "Buyer's Premium" (default) and "Auction House Commission" as the label displayed on lot pages. This overrides the Bidspirit JS client's default label using a MutationObserver that catches asynchronously injected text.
Files Changed
- Modified:
inc/controllers/Settings.php,templates/single-lot.php
---
[3.6.0.4] — 2026-04-12
Auction Approval Modal Redesign
Changes
- Removed BidSpirit Terms of Use — The generic BidSpirit "Terms of Use" section that appeared at the top of the non-credit-card approval modal has been removed. The modal now shows only the auction house's own legal agreements managed within the plugin.
- Renamed Modal Title — Changed "Terms of conditions" to "Terms & Conditions".
- Larger Scroll Area — The Terms & Conditions scroll box is now 350px tall (up from 200px) for easier reading.
- Proportional Section Heights — Refund & Return Policy and Chargeback Waiver sections use a shorter 260px scroll box to visually distinguish them from the primary Terms & Conditions.
Files Changed
- Modified:
templates/js-chunks/approval-info.php,assets/js/app.js
---
[3.6.0.2] — 2026-04-10
Webhook Token Generator
Features
- Token Generator Widget — Added a 16-character random token generator directly below the "Webhook auth token" field on the Settings page. Includes a "Generate Token" button and a clipboard copy icon with visual feedback.
Files Changed
- Modified:
inc/controllers/Settings.php
---
[3.6.0.1] — 2026-04-10
Patch
Changes
- Version bump.
---
[3.6.0.0] — 2026-04-10
Legal Agreements for Auction Approval
Features
- Terms & Conditions — A mandatory, scrollable Terms & Conditions document is now displayed during the auction approval process. Bidders must scroll to the bottom and check an agreement box before their approval request is submitted. Always enabled.
- Refund & Return Policy — An optional, scrollable Refund & Return Policy can be enabled in Settings. When enabled, bidders must read and accept it during auction approval.
- Chargeback Waiver — An optional, scrollable Chargeback Waiver can be enabled in Settings. When enabled, bidders must read and accept it during auction approval.
- Admin Management — New "Legal Agreements" page under the Bidspirit admin menu with tabbed TinyMCE editors for each agreement type. Includes automatic version numbering (incremented on content change) and full version history.
- Consent Logging — Every agreement acceptance is logged to a dedicated database table (
af_user_agreement_log) with the agreement type, version, user email, IP address, user agent, auction ID, and timestamp. - User Tracking Integration — Agreement events (
terms_agreement,refund_agreement,chargeback_waiver) are also recorded in the existing IP tracking system alongside registration, login, and bid events. - Placeholder Content — Default sample content is seeded on plugin activation for all three agreement types.
Settings Added
- Enable Refund & Return Policy — Toggle to require bidders to accept the refund policy during auction approval.
- Enable Chargeback Waiver — Toggle to require bidders to accept the chargeback waiver during auction approval.
Database
- New table:
af_legal_agreements— Current active agreement content per type - New table:
af_legal_agreement_versions— Version history archive - New table:
af_user_agreement_log— User consent records
Files Changed
- Modified:
auctionforge.php,inc/controllers/Settings.php,inc/controllers/BidspiritViews.php,inc/ip-logger.php,templates/js-chunks/approval-info.php,assets/js/app.js - Created:
inc/legal/class-legal-agreements.php,admin/view/legal-agreements.php
---
[3.5.0.6] — 2026-04-08
Bid Event Tracking
Features
- Bid Tracking — All successful bids (regular, catalog, pre-sale buyout, post-sale purchase) now fire
afLogIP("bid", bidspiritUser)to capture the bidder's full identity in the user tracking table. - Whitelist Update — Added
bidto the allowedevent_typevalues in both the local plugin and the central WPDeploy API.
---
[3.5.0.5] — 2026-04-08
Self-Healing Database Schema
Features
- Auto-Migration — The plugin now auto-detects and adds any missing tracking table columns on version upgrade, ensuring sites with older schemas seamlessly migrate without manual SQL.
---
[3.5.0.4] — 2026-04-08
API Key Auto-Healing
Features
- Seamless Self-Registration — The WordPress plugin now autonomously regenerates and saves a fresh API Key whenever WPDeploy rejects a payload with an
api_key_collisionerror. This guarantees zero-downtime security handovers when developers clone instances to proxy/staging servers.
---
[3.5.0.3] — 2026-04-08
API Key Collision Defense
Features
- 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_collisionerrors, directly instructing developers to update cloned keys.
---
[3.5.0.2] — 2026-04-08
Modal Trigger Hotfix
Fixes
- Restructured internal UI rendering priority to gracefully deploy the inline Modal triggers inside custom IP log view without colliding with cached
z-indexstacks.
---
[3.5.0.1] — 2026-04-08
Hotfix
Fixes
- Timed Auction Badge Visibility — Fixed a strict type-matching bug in the main
auction_list.phpcore file that incorrectly hid the "Timed Auction" badge overlay from valid timed/online auctions on the main upcoming/archive views. The badge now displays properly across all manual and Bidspirit-synced objects when toggled on.
Files Changed
- Modified:
templates/main/auction_list.php
---
[3.2.9.1] — 2026-03-30
Timed Auction Display Enhancements
Features
- Timed Auction Countdown Text Toggle — Added a WP-Admin setting "Change text to 'Auction will close in'" that conditionally changes the countdown label for timed/online auctions on single lot pages.
- Shortcode Text Toggle Support — Extended the new countdown text logic to the
bp_upcoming_wideshortcodes so "Live bidding starts in:" successfully transitions to "Auction will close in:" for timed auctions.
Files Changed
- Modified:
inc/controllers/Settings.php,templates/single-lot.php,templates/shortcodes/upcoming-auction-wide.php,templates/shortcodes/upcoming-auction-wide-manual.php
---
[3.2.9.0] — 2026-03-29
Billing & Invoices Polish
Fixes
- Profile Invoice ID Tracking — Prevented internal auction codes (e.g.
002orai4) from breaking into the clean hyphenated titles inside theprofile-templates.phpview. - Dynamic Payment Statuses — Replaced Bidspirit's default/cached
NOT PAIDHTML payloads by wiring thedompdfgenerator to directly respect the current$b.statusstring from the API (resolving instances where a paid invoice still printed "NOT PAID" atop the document). - Payment Instructions Conditional — Automatically hide the "Payment Instructions" block from the PDF footer when an invoice is fully paid.
- Improved Nomenclature — Changed "Invoice No:" to "Bidder No:" on document output to prevent confusion with static invoice ledger IDs.
---
[3.2.6.0] — 2026-03-28
Multi-Day Auction Lot Filtering Fix
Fixes
- Day 2+ showing lots from Day 1 in multi-day auctions — The
itemIndexcolumn inbp_meta_dataisvarchar(55), but the day-range filter inBidspiritQuery::bp_query_where()was comparing it as a string. With string comparison, lot numbers like'11','101'–'145'incorrectly fell between'1001'and'1450', causing Day 1 lots to leak into Day 2 results. Fixed by usingCAST(bpMeta.itemIndex AS UNSIGNED)for numeric comparison andintval()on the PHP-side boundary values. Letter lots (e.g.14A,1025A) are handled correctly —CASTstrips the suffix, keeping them grouped with their base lot number.
Files Changed
- Modified:
inc/controllers/BidspiritQuery.php
---
[3.2.5.9] — 2026-03-27
Catalog Page Fix
Fixes
- Duplicate preview hours on catalog pages — The
displayHoursfield was rendered twice: once via thebp_after_description_auctionhook inBidspiritViews.phpand once inline in the auction template. Removed the hook-based rendering to eliminate the duplication.
Files Changed
- Modified:
inc/controllers/BidspiritViews.php,templates/main/auction.php
---
[3.2.5] — 2026-03-19
Sync Reliability & Stuck Lot Prevention
Fixes
- CATALOG_PUBLISHED webhook now triggers catalog sync — Previously only sent push notifications without syncing lots. When the earlier AUCTION_CATALOG_UPDATED fired before the catalog was ready on BidSpirit, lots were never imported. CATALOG_PUBLISHED now calls
auctionCatalogUpdated()to trigger a full catalog sync when the catalog is actually available. - 0-lot API results now fail instead of silently succeeding — When BidSpirit API returns 0 lots (catalog not yet ready), the sync job now fails with an explicit error message, allowing the next webhook to create a fresh retry job.
- Expanded CDN allowlist in pre_http_request filter — The HTTP filter during bulk post insertion now allows all
*.bidspirit.comsubdomains and BidSpirit image CDNs (fastly.net,cloudfront.net). Previously onlybidspirit.comandwww.bidspirit.comwere allowed, blocking image downloads during sync and causing worker hangs. - InsertLotsBS timeout guard — Stage 5 (InsertLotsBS processing loop) now has a 180-second timeout and logs progress every 2 batches. Prevents indefinite hangs that previously required manual force-kill.
- fixResult() no longer marks lots as done when postId=0 — When
lotProcessing()fails to create a WP post, the staging row now keepssyncFinished=0so the lot is retried on the next sync pass, instead of being permanently marked as complete with no actual post. - lotProcessing() logs error on missing auction term — Previously returned 0 silently when
Auction::findAuctionById()failed. Now logs an explicit error that feeds intofixResult()to keep the lot retryable. - Hourly orphan detection in safety cron — New step in
syncSafety.phpdetects lot posts that exist inbp_meta_databut are missing their auction taxonomy assignment (caused by workers killed mid-batch) and auto-repairs them withwp_set_object_terms().
Files Changed
- Modified:
inc/controllers/AuctionsAPI.php,inc/sync/CatalogSyncWorker.php,inc/abs/InsertLotsAbstract.php,inc/import/InsertLotsBS.php,crontasks/syncSafety.php
---
[3.2.4] — 2026-03-18
Sync Worker Hang Fix
Fixes
- Sync workers hanging at InsertLotsBS stage — Third-party plugins (Smush Pro, SmartCrawl SEO, WPMU DEV Updates) hook into
wp_insert_post()and make blocking outbound HTTPS calls for every lot processed. With 489+ lots per auction, this caused workers to hang indefinitely on socket reads to WPMU DEV servers (32.193.94.25,32.193.93.106). AddedWP_IMPORTINGconstant at the REST worker entry point and apre_http_requestfilter inCatalogSyncWorkerthat blocks all non-essential external HTTP during the batch post-insertion phase. Loopback (127.0.0.1,localhost) and BidSpirit API calls remain allowed. - Stuck staging rows after force-kill — When workers were force-killed mid-sync, staging rows in
import_historywere left withsyncstart=1and never unblocked. Subsequent sync runs could not see these rows (filtered out byLot::getRawLots()), causing the InsertLotsBS loop to exit immediately with 0 posts processed. Combined with job deduplication (SyncQueue::enqueue()skips if aprocessingjob exists), this created a deadlock where no new sync could proceed.
Files Changed
- Modified:
auctionforge.php,inc/sync/CatalogSyncWorker.php
---
[3.2.2] — 2026-03-17
Full Sync Auction Discovery Fix
Fixes
- Full Sync finds no auctions on fresh sites — The v3
full_syncaction only queried the WordPress database for existing auction terms, but on a freshly deployed site the database has zero auctions. AddedAuctionList::init()discovery step before querying the DB, so Full Sync now fetches all auctions from the BidSpirit API and creates taxonomy terms first, then enqueues catalog sync jobs for each.
Files Changed
- Modified:
auctionforge.php
---
[3.2.0] — 2026-03-14
Webhook Pipeline Fixes, Archive Sync & Admin UI Overhaul
New Features
- Archive Sync — New "Archive Sync" button on Sync Status admin page. Enqueues catalog sync jobs for all ARCHIVED/ENDED auctions. Past auctions now appear in the auction dropdown with an optgroup separator and state label.
- Sync Tasks v3 — Replaced old v2 task cards (importData, importBidSpirit, lotBidSpiritOld) with v3 queue-based tasks. "Sync Active Auctions" and "Sync Archived Auctions" now enqueue jobs via the queue system. Maintenance tasks (Clean Draft/Trash Lots, Clean Orphaned Meta) remain as direct-execution tasks.
- How It Works guide rewritten — Complete rewrite of the admin guide for v3 architecture. Documents webhook-first flow, all 5 job types, queue system mechanics, cron setup (external + WP-Cron), configuration constants, and troubleshooting.
Fixes
- Dual-write removed — Removed legacy handlers from
auctionCatalogUpdated(),auctionDayEnded(), anditemsUpdated()webhook methods. The old handlers were racing with the v3 worker, creating orphaned staging rows inimport_historythat were never processed. All three methods now exclusively use the v3 enqueue → spawn path. - ITEMS_UPDATED webhook — Fixed
itemsUpdated()failing to enqueue jobs. TheITEMS_UPDATEDpayload hasauctionIdnested initemsByLanguage.{lang}[0].item.auctionId, not at the top level. Added extraction logic to resolve it. - ItemUpdateWorker incomplete —
ItemUpdateWorker::process()was only callingLot::bulkSave()(staging table) without runningInsertLotsBSto process staged data into WP posts andbp_meta_data. Added the InsertLotsBS processing step with autocommit restore. Item updates now flow: stage → InsertLotsBS → WP post + meta → cache clear. - Worker spawn reliability — Changed
SyncQueue::spawnWorker()from non-blocking HTTPS to blocking HTTP loopback (http://127.0.0.1with explicitHostheader, 2s timeout). Fixes nginx 403/404 errors when HTTPS loopback hits the default vhost instead of the site's vhost. - API token constant — Plugin expects
AUCTIONFORGE_API_TOKENinwp-config.php(renamed fromUCO_API_TOKENduring the plugin rename). Documented in readme.
Database
- DB version: 22 → 23
Files Changed
- Modified:
inc/controllers/AuctionsAPI.php,inc/sync/ItemUpdateWorker.php,inc/sync/SyncQueue.php,auctionforge.php,admin/view/sync-status.php,readme.txt
---
[3.0.0] — 2025-03-14
New Feature: Webhook-First Sync Architecture (Sync v3)
Overview: Complete redesign of the BidSpirit data synchronisation pipeline. Replaces the old two-phase polling system (importBidSpirit every hour + importData every minute) with a webhook-driven job queue that processes data in near real-time.
Architecture
- 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: webhook → queue → background worker → WordPress posts. - Dual-write mode — During transition, webhooks enqueue jobs AND still run the legacy handlers. Once verified, legacy handlers can be removed cleanly.
- Job deduplication — Prevents duplicate work by checking for existing pending/processing jobs with the same auction_id + job_type.
New Components
- Job Queue System (
inc/sync/SyncQueue.php) — Priority-based FIFO queue with atomic job claiming, status tracking (pending/processing/completed/failed/skipped), worker PID tracking, and automatic stuck job recovery. - Sync Logger (
inc/sync/SyncLogger.php) — Real-time log table for admin console polling with level filtering (info/success/warning/error) and incremental cursor-based retrieval. - Catalog Sync Worker (
inc/sync/CatalogSyncWorker.php) — Processes catalog_sync, full_sync, and day_ended jobs by reusing existingLotList::singleRun()logic. - Item Update Worker (
inc/sync/ItemUpdateWorker.php) — Processes individual item_update jobs with the same logic as the webhookitemsUpdatedhandler. - Background Worker (
crontasks/syncWorker.php) — Async CLI process spawned by webhooks viaexec()or by the safety cron. Claims and processes queued jobs with a configurable timeout (default 240s). - Safety Net (
crontasks/syncSafety.php) — Hourly cron that resets stuck jobs (>10min), spawns workers for pending jobs, runs a 24-hour health check (auto-enqueues full sync if no webhooks received), and purges old data.
Admin UI
- Queue Status Dashboard — New card on Sync Status page showing pending/processing/completed/failed/skipped counts, recent jobs table with real-time refresh, worker status badge, and action buttons:
- Full Sync — Enqueues catalog sync for all active auctions
- Sync Selected — Enqueue a single auction from dropdown
- Spawn Worker — Manually trigger a background worker process
- Live Console — Dark-themed terminal console on the Sync Status page. Polls
af_sync_logevery 1.5s showing timestamped, color-coded log entries from webhooks, workers, queue operations, and the safety cron. Supports pause, clear, and auto-scroll.
Cron Changes
- Removed
importData(ran every minute — ~1,440 PHP executions/day) - Removed
importBidSpirit(ran hourly — ~24 PHP executions/day) - Added
syncSafety(runs hourly at :10 — 24 PHP executions/day) - Net effect: ~62 PHP executions/hour → 1 PHP execution/hour
- WP-Cron safety hook (
auctionforge_sync_safety) — Always-active hourly event, independent of external cron - setup.sh v3 — Updated task definitions, new
migratecommand for interactive v2→v3 transition
Database
- New table:
af_sync_queue— Job queue with status, priority, source, attempts, worker PID, timing columns - New table:
af_sync_log— Real-time log entries with context, level, auction_id, job_id - DB version: 20 → 22
Constants Added
| Constant | Default | Description |
|---|---|---|
|
AUCTIONFORGE_SYNC_WORKER_TIMEOUT| 240 | Worker process timeout in seconds ||
AUCTIONFORGE_SYNC_STALE_JOB| 600 | Seconds before a processing job is considered stuck ||
AUCTIONFORGE_SYNC_HEALTH_CHECK| 86400 | Seconds without webhook before triggering full sync ||
AUCTIONFORGE_SYNC_LOG_RETENTION| 7 | Days to keep log entries ||
AUCTIONFORGE_SYNC_QUEUE_RETENTION| 30 | Days to keep completed queue jobs ||
AUCTIONFORGE_CURL_TIMEOUT| 30 | BidSpirit API cURL timeout in seconds ||
AUCTIONFORGE_PHP_BINARY| /www/server/php/83/bin/php | PHP CLI binary path for spawning workers |AJAX Handlers Added
auctionforge_sync_log_poll— Incremental log polling for live consoleauctionforge_sync_queue_status— Queue counts + recent jobs for dashboardauctionforge_sync_enqueue— Admin-triggered sync actions (full_sync, sync_auction, spawn_worker)
Fixes
- cURL timeout — BidSpiritRequest now enforces a 30-second timeout (was unlimited/0), preventing hung connections from blocking the sync pipeline.
Files Changed
- Modified:
auctionforge.php,inc/coreIncludes.php,inc/controllers/AuctionsAPI.php,inc/BidSpiritRequest.php,admin/view/sync-status.php,crontasks/setup.sh - Created:
inc/sync/SyncQueue.php,inc/sync/SyncLogger.php,inc/sync/CatalogSyncWorker.php,inc/sync/ItemUpdateWorker.php,crontasks/syncWorker.php,crontasks/syncSafety.php
---
[2.7.3.0]
Fixes
- Various stability improvements and bug fixes.
[2.7.1.2]
Fixes
- Added missing
vatAndCommission()function inloadBid()— the sales tax display on single lot pages was never being rendered because the code to callloadTemplateforvat-and-commission-templatewas missing fromapp.js.
[2.7.1.1]
Fixes
- 2 decimal places now only appear in the bid modal (Your max bid, Total Price) via
showDecimalsflag. 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.
[2.7.0.9]
Fixes
- Fixed fatal error during plugin install/upgrade:
class-stats-database.phprequire failure.
[2.7.0.0]
New Features: Advanced Lot Analytics
- Conversion Tracking, Peak Viewing Times, Pre-Sale vs Live Comparison, Category Performance, Share Analytics, Search → View Funnel, Click-Through Tracking, CSV Export, Hot Lot Badge.
- New DB table:
af_lot_shares. New columns onaf_lot_analytics. DB version bumped to 20.
[2.6.0.0]
New Feature: Lot Analytics
- Comprehensive lot view and favorite tracking system with admin dashboard.
[2.5.0.0]
New Features
- Site Statistics System — Full website analytics built into the plugin admin.
- Recently Viewed Items — Profile page tab showing last 20 viewed lots per user.
- Run Identity Check — calls the new wpdeploy
-
v3.7.0.26 Stable May 13, 2026Download v3.7.0.26📦 9.16 MB⚙️ WP 5.2+🔧 PHP 7.2+✓ Tested 6.4
AuctionForge Changelog
All notable changes to the AuctionForge plugin are documented in this file.
---
[3.7.0.21] — 2026-05-05
Added — Connection Diagnostics on the Updates admin page
A new Connection Diagnostics card on Lots → Updates that detects and one-click-heals identity mismatches between this site and the deployment server.
The problem it solves. When a WordPress install is cloned (template → customer site, dev → prod, backup → restore), the cloned wp_options carry the original site's
auctionforge_update_api_keyover to the newhome_url(). The new install then makes API calls to wpdeploy *authenticated as the original site*. wpdeploy looks up by api_key, not by URL, so every/sync-user-tracking,/check-updates,/report-health, and most importantly the Kuma push URL, gets recorded against the WRONGwpdeploy.sitesrow. The cloned site's monitor stays silent; the original's monitor shows traffic that isn't from it.What the diagnostic does:
- Run Identity Check — calls the new wpdeploy
GET /api.php/whoamiendpoint and compares the returnedcaller_site_urlagainsthome_url(). Renders a verdict ("matches" / "MISMATCH") plus the full server-side view (site_id, site_name, last_check, plugin version on file, remote IP). The "Re-register & Reset Kuma" button only appears if there's a mismatch. - Re-register & Reset Kuma — calls
/request-access(which is idempotent onsite_url— wpdeploy returns the canonical api_key for *this*home_url(), regardless of whatever wrong key we were holding), wipesauctionforge_kuma_push_urland any leftover heartbeat cron events, then immediately fires/check-updatesso the api_request interceptor catches the freshly-correct kuma_push_url for *this* site. The keepalive mu-plugin's heartbeat picks it up on the next 60s tick.
Internal
AuctionForge_Auto_Updater::whoami()(new) — thin wrapper overapi_request('whoami', [], 'GET'). Returns the parsed wpdeploy/whoamipayload.AuctionForge_Auto_Updater::reset_connection()(new) — three-step heal: re-register → wipe Kuma cached state → re-fetch via/check-updates. Returns shape suitable forwp_send_json_success.- Two new AJAX actions:
auctionforge_diagnose_connection,auctionforge_fix_connection. Both behindmanage_optionscapability + nonce check. auctionforge_normalize_host()helper for case/scheme/www-tolerant URL comparison.
Server-side companion
Requires the wpdeploy
/api.php/whoamiendpoint added in the same release window. The endpoint is gated behind whatever api_key the caller already presented (a master key returnstype=masterwith no site row; a per-site key returns the site row that key resolves to). Reveals nothing the caller doesn't already implicitly authenticate against.---
[3.7.0.20] — 2026-05-04
Changed
- Kuma heartbeat path is now wpdeploy-independent. The actual heartbeat firing — wp-cron schedule, page-load piggy-back, outbound HTTP — moved out of AF and into the AuctionForge Keepalive mu-plugin (
wp-content/mu-plugins/auctionforge-keepalive.php, bumped to v1.2.1). Once a site has been provisioned once andauctionforge_kuma_push_urlis cached locally, the heartbeat keeps reporting forever even if AF is deactivated, mid-upgrade, deleted from disk, or wpdeploy is offline. The mu-plugin can't be deactivated by WordPress, can't be broken by an AF release, and depends on AF for nothing. - AF only writes the
kuma_push_urloption now. It no longer schedules the cron, no longer fires the heartbeat, and no longer holds any heartbeat-related state. Theapi_request()interceptor still catcheskuma_push_urlfrom/check-updatesand/report-healthresponses and persists it; the mu-plugin reads it from there. - Migration block.
init_hooks()clears any leftoverauctionforge_kuma_heartbeatwp-cron event from AF ≤ 3.7.0.19 on first plugin load after upgrade. The mu-plugin runs the same clear on its ownplugins_loadedhook — belt and braces. The new event the mu-plugin schedules iskuma_heartbeat_tickon a newkuma_60sschedule. AuctionForge_Auto_Updater::kuma_heartbeat()no-opped. Kept as a safety landing pad so any staleauctionforge_kuma_heartbeatwp-cron event that fires one last time before migration kicks in doesn't trip a "no callback registered" warning. Real heartbeat work happens in the mu-plugin.
Added — operator override
AUCTIONFORGE_KUMA_PUSH_URLconstant. Define it inwp-config.phpto point a site directly at Kuma without ever involving wpdeploy:
```php
define('AUCTIONFORGE_KUMA_PUSH_URL', 'https://kuma.example.com/api/push/<token>?status=up&msg=&ping=');
```
The constant takes precedence over the
auctionforge_kuma_push_urloption. With it set, the site can be operated fully outside wpdeploy — useful for one-off installs, customer-managed sites, or disaster-recovery scenarios where wpdeploy is unreachable for an extended period.Internal — Keepalive mu-plugin v1.2.1
The bundled keepalive template at
inc/keepalive/auctionforge-keepalive.template.phpnow also handles Kuma heartbeats. Three layered triggers ensure cadence stays tight regardless of site traffic:1. Dedicated wp-cron event
kuma_heartbeat_tickon a new 60-secondkuma_60sschedule2. Page-load piggy-back on
init: any request older than 50s since the last beat fires another, transient-guarded so concurrent hits coalesce. Free on busy sites; rescues low-traffic sites the moment any visitor arrives.3. Self-heal inside the cron callback: if the event somehow gets cleared, re-arm it before sending the beat.
HTTP is
timeout=2, blocking=false— fire-and-forget, never slows page loads. External IP introspection (ipify → ifconfig.me → icanhazip fallback chain, 24h transient cache) is duplicated in the mu-plugin so it doesn't depend on AF being loaded for the IP lookup.The keepalive installer (
class-keepalive-installer.php) detects theKEEPALIVE_VERSION: 1.2.1header bump and idempotently overwrites every site's mu-plugin on the next AF load. No manual reactivation needed.Failure modes after this release
| State | Heartbeat? |
|---|---|
| AF active and healthy | ✅ via mu-plugin |
| AF deactivated by an operator | ✅ mu-plugin runs anyway |
| AF deleted from disk | ✅ as long as
auctionforge_kuma_push_urloption exists OR constant is set || AF mid-upgrade / partial install | ✅ mu-plugin doesn't depend on AF code paths |
| wpdeploy down (existing site) | ✅ option is cached locally, no wpdeploy round-trip |
| wpdeploy down (brand-new site, never provisioned) | ❌ first-time URL provisioning still needs wpdeploy. One-shot, accepted trade-off. |
| Site has zero traffic AND wp-cron isn't firing | ❌ truly nothing to trigger a beat. Mitigation is OS-level cron / DISABLE_WP_CRON, out of scope here. |
---
[3.7.0.19] — 2026-05-04
Changed
- Reverted Kuma heartbeat cadence: 3 min → 1 min.
auctionforge_kuma_heartbeatis back on thebp_minutelyschedule. With Kuma's 310s silence window, 60s cadence tolerates 4 missed wp-cron ticks before flipping a monitor red — the original "give-it-leeway" semantics. The 3-min cadence introduced in 3.7.0.18 was strictly less chatty but tighter (a single missed tick would trip Kuma), and the trade-off wasn't worth it operationally. - Migration block updated.
init_hooks()now detects any existing event scheduled on a non-bp_minutelycadence (e.g. thebp_3_minutelyset by 3.7.0.18) and re-schedules ontobp_minutely. Sites that took 3.7.0.18 roll back automatically on first plugin load after upgrade. - First-fire jitter narrowed back to 0–60s to match the new cadence.
Notes
- The
bp_3_minutelycron schedule registration inauctionforge.phpis kept (harmless; available for future use). Only the heartbeat scheduling sites have been reverted. - Apparent latency in Kuma flipping a monitor red after a real outage is governed by Kuma's per-monitor
interval(silence-detection window, currently 310s on the wpdeploy/Kuma side), not by this cron's cadence. To detect outages faster, lower the Kumainterval; to add more tolerance to wp-cron drift, raise it.
---
[3.7.0.18] — 2026-05-04
Changed
- Kuma heartbeat cron cadence: 1 min → 3 min.
auctionforge_kuma_heartbeatnow runs on a newbp_3_minutelyschedule (180s) instead ofbp_minutely(60s). This pairs with Kuma's 310s silence-detection window — a single late wp-cron tick (3 min + drift) still lands inside the threshold, but normal traffic to Kuma drops by ~3×. - Random first-fire offset widened from 60s → 180s. With ~50 sites on a single Kuma instance, spreading first-fires across the full 3-min window prevents synchronised bursts every 3 minutes.
- Auto-migration of existing scheduled events. On plugin upgrade
init_hooks()callswp_get_scheduled_event('auctionforge_kuma_heartbeat')and, if the existing event is onbp_minutely, clears it and reschedules ontobp_3_minutely. Idempotent — a no-op once migrated.
Internal
- New cron schedule registered:
bp_3_minutely(BP_MINUTELY * 3= 180s). Defined alongside the existingbp_minutely/bp_ten_minutely/bp_hourly/bp_24_hourlyschedules inauctionforge.php.
---
[3.7.0.17] — 2026-05-04
Fix: "Install Now" always returned
up_to_dateThe
/sync/versionREST endpoint (called by wpdeploy's Install Now button) was always respondingsuccess: false, reason: up_to_dateregardless of the actual installed version, defeating the button's whole purpose.Root cause
rest_force_plugin_update()did:```
delete_site_transient('update_plugins');
$this->check_pending_updates();
$updates = get_site_transient('update_plugins');
```
check_pending_updates()calls the/pending-updatesendpoint on wpdeploy (which returns the deploy queue), but it does not touch the WPupdate_pluginstransient. The transient just got deleted on the line above and never gets re-populated, so theisset($updates->response[…])check always failed → always returnedup_to_date.Fix
- Use
wp_update_plugins()instead — that's what fires thepre_set_site_transient_update_pluginsfilter chain that AF's owncheck_for_updates()callback hooks into to seed the transient. Same pattern is already used correctly ininstall_update()at line 280. - Belt-and-braces: when the request body carries an explicit target
versionand that version is strictly greater than the on-disk plugin version (perversion_compare), bypass the transient check and force the install. This handles edge cases where the transient seeding fails (network blip during the wp-cron cycle, hosting-side cache, etc.) so the explicit Install Now command still does what it says.
---
[3.7.0.16] — 2026-05-04
Server external IP reported to wpdeploy + included in Kuma heartbeats
Each AF install now reports its server's outbound external IP. Two channels:
1. Kuma heartbeat
msg— the per-minute push payload now reads<wp_version>|<plugin_version>|<external_ip>(e.g.6.9.4|3.7.0.16|152.53.187.82) so you can spot at a glance which physical box each site lives on. When a host goes dark, multiple monitors flip red simultaneously with the same IP — instant root-cause hint.2.
/report-healthpayload — a newexternal_ipfield that wpdeploy stores onsites.external_ip. Visible in the Sites admin view as a tappable IP chip; clicking it filters the table to all sites sharing that IP.How the IP is detected
AuctionForge_Auto_Updater::get_external_ip()calls one of three public echo services in turn —api.ipify.org,ifconfig.me/ip,icanhazip.com— with a 4-second timeout each. The first one that returns a valid IP wins. Result is cached in a transient for 24 hours so we don't hit external services on every report cycle.Wpdeploy fallback for older plugins
/report-healthnow also capturesREMOTE_ADDR(orHTTP_CF_CONNECTING_IPwhen behind Cloudflare) when the payload doesn't includeexternal_ip. So sites still on 3.7.0.15 or older start populating their IP today via the same route, no plugin update needed for that data path.---
[3.7.0.15] — 2026-05-04
Kuma monitors land in an "Unallocated" group by default
New AuctionForge installs are auto-enrolled into Kuma under a new top-level group called Unallocated so the operator can review them and drag-drop into the right home (Bidspirit Auction Sites, Stephen's Auctions, Misc Websites, etc.) before classification. Without this every new monitor would appear at the dashboard top level alongside whatever group hierarchy already exists.
What changed (wpdeploy-side, no plugin behaviour change)
KumaProvisionernow ensures an "Unallocated" group exists in Kuma (find-or-create via the same Socket.IOaddpath used for monitors, withtype='group') before provisioning each new push monitor, and passesparent=<group_id>in theaddpayload so the new monitor lands inside it.- The Node helper accepts arbitrary
typeandparentfields on the input payload (previously hardcoded totype='push'). - The group itself gets the same
user_id=1reassignment so it shows up on the human admin's dashboard.
Existing Clumber monitor (id=71) was migrated into the new group as part of this release.
This is a wpdeploy infrastructure change — the AF plugin code is unchanged from 3.7.0.14. Version bumped only to mark a clean snapshot point.
---
[3.7.0.14] — 2026-05-04
Uptime Kuma push heartbeat with automatic enrolment
Each AF install now appears as its own monitor on the central Uptime Kuma at https://kuma.smoothbyteit.dev, beating every minute and flipping red within ~90 seconds when a site goes dark. Auto-enrolled — no manual Kuma UI clicks per site.
How it works
1. First contact: when the plugin calls
/request-accessor/report-health, wpdeploy's newKumaProvisioneropens a Socket.IO connection to Kuma as a dedicatedauctionforge-botuser, calls the officialaddevent, and gets back a fresh push token. The resulting URL is shipped to the plugin in the JSON response askuma_push_url.2. Plugin-side: a generic interceptor on
api_request()persistskuma_push_urlto the optionauctionforge_kuma_push_urlwhenever it appears in any wpdeploy response, and immediately schedules the newauctionforge_kuma_heartbeatcron on the existingbp_minutelyinterval.3. Heartbeat: the cron handler sends a single
wp_remote_getto the push URL each minute withmsg=<wp_version>|<plugin_version>so Kuma's dashboard shows the running stack at a glance. Kuma's silence-detection window is 90s, so a single missed wp-cron tick won't false-DOWN.4. Idempotency: the Kuma monitor's
descriptionfield storeswpdeploy_site_id:<id>. Re-registering the same site short-circuits at the wpdeploy layer (existingkuma_monitor_idonsites), or — if that's missing — Kuma's existing row is reattached via the description anchor. Re-installing the plugin never duplicates monitors.Why Socket.IO and not direct DB insert
Kuma's monitor scheduler does not poll its own DB for new rows —
startMonitors()only loads monitors at boot, and new ones are armed via the authenticated Socket.IOaddevent handler (which callsstartMonitor()and arms the per-monitorsafeBeatsetTimeout). A direct INSERT would create a "phantom" monitor that accepts pushes but never flips DOWN on silence, defeating the whole feature.Notifications + monitor ownership
Provisioner reads existing Kuma notification rows whose channel is Telegram (or marked default-for-new-monitors) and attaches them to every new monitor via the
addevent'snotificationIDList. After the Socket.IOaddsucceeds, the provisioner direct-writesuser_id=1to the new monitor row in Kuma's SQLite — Kuma'saddhandler hardcodesuser_id=socket.userID(the bot at user 2), which causes the frontend's real-time monitor-list updates to skip the admin's session. The follow-up UPDATE stamps ownership to the human admin so monitors render with their full name on the admin dashboard immediately.Failure modes
Every call boundary degrades safely. If Kuma is unreachable when a site registers, registration completes without
kuma_push_url; the next twicedaily/report-healthretries. Heartbeat HTTP failures are silent (which is the desired outcome — Kuma's silence-detection is the signal). Kuma reset / monitor row deleted: provisioner's pre-flight check NULLs the wpdeploy anchors and falls through to fresh provisioning on the next call.Operator setup
Already done: the
auctionforge-botKuma user has been created and credentials populated in wpdeploy'sconfig.php. To rotate or migrate Kuma later, editKUMA_URL/KUMA_BOT_USER/KUMA_BOT_PASSinconfig.php— no plugin redeploy needed.---
[3.7.0.13] — 2026-05-04
Wide shortcode: hide Register button for logged-in users
- When a user is logged in to BidSpirit (
body.bp-login), the Register button is now automatically hidden on wide-format auction cards (bp_upcoming_wideandbp_auction_list layout="wide"). - The View Catalog / Catalog Coming Soon button expands to full width when the Register button is hidden.
- Uses a lightweight
MutationObserverto react to BidSpirit's async session init. - Applied to both
UpcomingAuctionWide.phpandAuctionList.phpshortcode CSS blocks.
---
[3.7.0.12] — 2026-05-03
Stop-word denylist for BidSpirit category-tag concatenations
BidSpirit's
wp_bp_meta_data.tagsfield arrives as PascalCase category names lowercased without separators (uscollectibles,firearmsaccessoriesammunition,usdecorativearts,printsandmultiples). They look like keywords but they're really categories, and on sites where the tags field is populated they completely swamp the top-5 chips for power users (e.g. one buyer's profile was led byuscollectibles 453 viewsdespite that being a label rather than a real interest signal).29 known patterns added to
stop-words.phpso the tokenizer drops them at extraction time. New ones surfacing from sites we haven't seen yet should be added here as they appear; the wpdeploy?tab=keywordscorpus page makes them easy to spot (sort by most users with low lots count and look for non-word concatenations).---
[3.7.0.11] — 2026-05-03
Keyword extractor — capture model years + hyphenated calibers, drop more auction noise
The People view's top-5 keyword chips were filling up with generic descriptors (
household,model,original,assortment) instead of the brand/maker terms (mauser,whitworth,colt) that actually distinguish one buyer from another. Live-data review on the new?tab=keywordsKeyword Corpus page on wpdeploy confirmed the cause: real signal was being lost at the tokenizer stage.Tokenizer changes (
inc/stats/class-keyword-extractor.php)Three pre-passes now run before the standard split-on-non-alpha:
1. Hyphenated / x-separated calibers —
.45-70,.30-06,7.62x54r,8x57. Without this they're split into pure-digit fragments and dropped, losing the actual model identifier.2. Caliber-with-suffix —
9mm,.22lr,.45acp,.380acp. Previously only survived by accident because of the trailing letters; now extracted explicitly.3. 4-digit model years 1700–2099 —
1873,1903,1911,1971. Pure-digit tokens were unconditionally dropped; now retained when year-shaped.Standard pass relaxed to allow 4-digit pure-digit tokens between 1700 and 2099.
Stop-word additions (
inc/stats/stop-words.php)Conservative — only universally empty auction descriptors:
original,marked,accessories,decorative,household,goods,made,condition,assortmentDeliberately NOT added:
antique,vintage,rare,fine— those carry buyer-segmentation signal (antiquarian buyers vs. modern-collectibles buyers). Borderline cases (metal,wooden,american,model) are left to the wpdeploy-side IDF re-rank.Companion change on wpdeploy (no plugin update needed)
refresh_people_rollup.phpnow multiplies each keyword's score by an IDF factor pulled fromkeyword_idf(refreshed hourly byrefresh_lot_keyword_index.php). Generic keywords that appear in many lots get demoted automatically; brand/maker words that only appear on a handful get lifted into the top-5 chips.After deploying this version, reset the
auctionforge_lots_sync_watermarkoption on each site and clear thewp_af_stats_lot_keywordstable to force re-extraction of every lot through the new tokenizer.---
[3.7.0.10] — 2026-05-03
Lots sync — ship resolved CDN image URL, not bare BidSpirit filename
class-lots-sync.phpwas sendingimagesListStr's first comma-token verbatim asimage_url— that's the raw BidSpirit storage value (e.g.001.jpg). Wpdeploy received a bare filename, the browser resolved it against the wpdeploy host, and every lot thumbnail 404'd.The lots-sync now instantiates
LotImageand pulls the resolved CDN URL (LABEL_MEDIUMthumbnail), with fallback toLABEL_ORIGINALand a final defensive check that drops anything that doesn't start withhttp(s)://. Resolution is wrapped in try/catch — a missing class or BidSpirit settings issue leavesimage_urlempty rather than blowing up the sync batch.After deploying this version on a site, reset its
auctionforge_lots_sync_watermarkoption (delete the row) to re-push existing lots through the new resolver. The wpdeploy view skips<img>rendering whenimage_urlisn't a real URL, so dirty rows degrade silently while the watermark catches up.---
[3.7.0.9] — 2026-05-03
Keepalive sweep — auto-clears WP upgrader debris that produces silent "Could not create directory" failures
WordPress 6.x's atomic-rollback flow leaves
wp-content/upgrade-temp-backup/lying around when its post-install cleanup misfires (the user-facing symptom is "Update failed: Could not create directory" after an update that has actually already succeeded). Stalewp-content/upgrade/<plugin>-tmp/and.maintenancelockfiles from crashed upgrades cause the *next* upgrade attempt to fail the same way. None of WP's own scheduled cleanup catches these reliably.The keepalive mu-plugin (
KEEPALIVE_VERSION1.1.0) now sweeps all three classes of debris on every page load, transient-guarded to once per hour. Safety thresholds prevent it touching anything actually in flight:.maintenancefiles less than 5 min old,wp-content/upgrade/*entries less than 60 min old, andupgrade-temp-backup/less than 30 min old are left alone. Wrapped in try/catch with no throws, so the sweep can never block a request.The keepalive installer detects the version bump and rewrites
wp-content/mu-plugins/auctionforge-keepalive.phpautomatically on the next AF load, no manual reactivation needed.---
[3.7.0.8] — 2026-05-03
Shop auction UI refinements & share button settings
Shop (Buy-It-Now) catalog improvements
- Shop sorting dropdown: Added a dedicated sorting dropdown for shop catalogs with options: Recently Added, Price: High, and Price: Low. Sorts by
buyoutPricemetadata. Regular auction catalogs retain the original sorting options. - Removed "Buyout price:" label: On shop lot pages, the redundant "Buyout price:" text before the price is now hidden. Only the price and "Buy Now" button are displayed. Regular auction buyout lots still show the label.
- Removed increments table & terms links: On shop lot pages, the "Increments table" and "Terms and conditions" links are hidden since they don't apply to buy-it-now items. The "Make an inquiry" link remains.
Buyout confirmation modal overhaul
- Sales tax logic: The buyout confirmation modal now follows the same sales tax detection as the regular bid modal. When the auction house has a US state configured, displays "Sales Tax" instead of "VAT", with the correct percentage for same-state buyers and 0% for out-of-state.
- Hide 0% buyer's premium: The Buyer's Premium line is hidden when the commission is 0%.
- Shop-specific text: For shop buyouts, all disclaimer text is replaced with: *"You will receive an email with your invoice, including shipping, and a secure payment link."*
- Shop-specific buttons: "I don't Agree" → "Cancel", "I Agree" → "Buy". The "Terms of sale" button is removed for shop buyouts. Non-shop buyouts retain the original layout.
Purchase confirmed screen
- Title changed from "Confirm purchase:" to "Purchase Confirmed".
- Thank you message updated to: *"Thank you for your order. We will confirm your order within 1-2 business days and email you an invoice, including shipping, and a secure payment link."*
Share button settings (Appearance tab)
- Added a Share Buttons section to the BidSpirit Appearance settings tab with individual checkboxes for each sharing platform: Copy Link, WhatsApp, Facebook, Telegram, X (Twitter), VK, Pinterest, and Email.
- All platforms default to enabled (shown). Unchecking a platform hides that share button on all lot pages (both shop and regular auctions).
---
[3.7.0.7] — 2026-05-02
Identity stitch on bidder login — keyword interest tallying now actually fires
Why
The keyword extractor was filling
wp_af_stats_lot_keywordscorrectly (197 lots, 734 distinct keywords on Clumber), butwp_af_user_interestsandwp_af_user_recent_activitywere both empty — zero rows of any dimension. Same on every site running the new sync streams.Root cause: identity stitching (visitor_hash → email) only fired in the tracker AJAX when
is_user_logged_in()returned true. On these auction sites the actual bidders authenticate via BidSpirit, never aswp_users— so the WP login check was always false, the stitch table stayed empty, andmaybe_record_lot_view($url, $email, …)got called with an empty email and bailed out before tallying. Lot views by real bidders never landed in the user-side interest profile.What changed (no auth-path intervention)
The fix piggybacks on the *existing* fire-and-forget tracking AJAX that already runs after a successful BidSpirit login (
afLogIP("login", bidspiritUser)). It does not touch the BidSpirit auth path itself.inc/ip-logger.phpauctionforge_ajax_log_ip()— after the existingauctionforge_user_trackinginsert, if the request carries avisitor_hashand the email is valid, callsAF_Stats_Visitor_Email_Map::record($vh, $email, $ip). Wrapped in try/catch so any failure here can never break the existing tracking response.assets/js/app.js+src/js/app.jsafLogIP()— readslocalStorage['af_vid'](defensively, ITP/private-mode safe) and includes it asvisitor_hashin the POST body.inc/stats/class-stats-init.phpmaybe_record_lot_view()— when$emailis empty (the common case for BidSpirit-only bidders) but avisitor_hashis present, falls back toAF_Stats_Visitor_Email_Map::lookup($visitor_hash). If a stitch exists, the view tallies; if not, it stays anonymous.
Net effect: a bidder logs in (BidSpirit), the post-login tracker AJAX fires as it always has, and now also writes one extra row into
af_stats_visitor_emails. From that point onward, every page they view on the same browser/device tallies intoaf_user_interestskeyed on their email. The BidSpirit transaction itself is untouched.---
[3.7.0.6] — 2026-05-02
Critical fix —
X-API-Keyheader collision with sibling SmoothByte pluginsWhat was wrong
On any site running both AuctionForge and another SmoothByte-stack plugin that also points its updater at
wpdeploy.smoothbyteit.dev(e.g.seo-aeo-optimizer), the second plugin'shttp_request_argsfilter overwrote AuctionForge'sX-API-Keyheader on every outbound API call. Wpdeploy then 401'd because the key it received belonged to a different plugin instance — usually aseo_aeo_update_api_keythat wpdeploy had no record of.The symptom was a quiet, total auth failure:
report-health,check-updates, everysync-*route, all 401. The watchdog flagged streams as "gone" and updates stopped flowing. Affected sites: any install where the AuctionForge key and the sibling plugin's key happen to differ. Sites where both plugins shared a key were silently safe (the overwrite was a no-op).Fix
AuctionForge_Auto_Updater::add_download_auth()now refuses to clobber an existingX-API-Keyand, for download URLs, only stamps when the URL slug matches our own. That keeps targeted calls fromapi_request()intact regardless of filter ordering, and prevents either plugin from writing its key onto the other's download URL.The same fix has been applied to
seo-aeo-optimizerso both ends of the collision are defensive.---
[3.7.0.5] — 2026-05-02
Sync Status admin panel — diagnostic + manual triggers in wp-admin
Why
Diagnosing sync issues used to require shell access on the site or piecing together state from wpdeploy's app.log. This release surfaces the same diagnostics inside wp-admin so a site admin (or anyone with
manage_options) can see exactly what's happening and trigger fixes in one click.Lives inside the existing Sync Status menu (
Lots → Sync Status) — appended below the existing content as a "Sync Diagnostics & Manual Controls" section, no duplicate menu entry.What's on the panel
Connection summary — plugin version,
af_stats_db_version, wpdeploy server URL, last 8 chars of API key, keepalive install state + auto-reactivation count.Sync streams table — for each of the 10 cron hooks (user-tracking, user-profile, user-interests, user-activity, lots, bids+wins, vulnerabilities, report-health, check-updates, fraud-enforcement):
- Configured schedule
- Last fired timestamp + status colour-coded (green=success, blue=idle/empty, red=error)
- Record count from last run
- Next scheduled run
- Current watermark (where applicable)
- "Fire now" button — clears doing_cron, calls
do_action($hook)synchronously, shows the result
One-shot utilities
Test wpdeploy connection— calls/api.php/infowith the site's API keyClear stuck cron lock— deletes thedoing_crontransient (the classic fix when scheduled events stop firing)Reinstall keepalive— overwritesmu-plugins/auctionforge-keepalive.phpfrom the bundled templateBackfill bids from legacy tracking— replayslast_event_type='bid'rows fromwp_auctionforge_user_trackingintowp_af_bid_eventsso the bids-wins stream picks them up. Useful for sites that have years of bid history in the legacy table but nothing in the new queueRun all due events now— clears doing_cron and fires everyauctionforge_*cron event whose timestamp is past due, in one go
Live response output panel shows the JSON returned from each action so you can see what just happened without leaving the page.
Files Changed
- Created:
inc/admin/class-sync-status-page.php - Modified:
inc/stats/class-stats-init.php(load + init the panel) - Modified:
admin/view/sync-status.php(appendAF_Sync_Status_Page::render_panel()call at the bottom) - Modified:
auctionforge.php(Version 3.7.0.4 → 3.7.0.5)
Verification
Navigate to Lots → Sync Status in wp-admin on any 3.7.0.5 site. Scroll past the existing content to the new "Sync Diagnostics & Manual Controls" section. Click "Test wpdeploy connection" — you should see
{"success": true, "auth_type": "site"}. Click "Fire now" on any stream — the row's last-fired timestamp should refresh after 1–2 seconds.---
[3.7.0.4] — 2026-05-02
Self-healing: failed plugin updates can no longer take a site offline
Why
WordPress's plugin updater isn't transactional — when an update fails partway (corrupt unzip, fatal during the new version's
plugins_loaded, disk pressure, theme conflict, etc.) WP often deactivates the plugin and leaves the site without it. Once AuctionForge is dropped fromactive_plugins, no AF code runs again — including its sync handlers — until someone notices and reactivates manually. On the AuctionForge site fleet, this had quietly happened to ~5 sites we found; almost certainly more on production sites we don't have filesystem access to.This release ships an autonomous watchdog that lives outside the AuctionForge plugin entirely so it survives even when AF gets knocked out.
What changed
1. Self-installing keepalive (mu-plugin)
inc/keepalive/auctionforge-keepalive.template.php— a 50-line WordPress must-use plugin. Lives inwp-content/mu-plugins/, which WordPress can't deactivate. On everyplugins_loaded(priority 1, before any regular plugin), it checks: isauctionforge/auctionforge.phpon disk but missing fromactive_plugins? If yes AND the file has a validPlugin Name:header (smoke check — don't reactivate a corrupt zip), it re-adds AF andincludes the file in the same request.inc/keepalive/class-keepalive-installer.php— runs on every successful AF load. Copies the template intowp-content/mu-plugins/auctionforge-keepalive.phpif missing or version-bumped. Idempotent: comparesKEEPALIVE_VERSIONheaders, only writes on change. Refuses to overwrite a foreign mu-plugin (defensive against name collisions). Failure is non-fatal — install errors are recorded inwp_optionsfor wpdeploy visibility but never throw.
Net effect. Any site that successfully loads AF 3.7.0.4 or later will have the keepalive permanently installed in mu-plugins. From that point forward, even if a future update hard-fails, the keepalive recovers AF on the next pageview without any manual intervention or filesystem access. Crucially: this works on sites we don't own — the keepalive ships inside the AF zip, gets installed during the first successful update, and lives in mu-plugins thereafter.
2. Forensic markers
The keepalive writes three options on each recovery:
auctionforge_auto_reactivated_at— most recent recovery timestampauctionforge_auto_reactivated_count— total recoveriesauctionforge_auto_reactivated_failed_at— set when the keepalive saw AF on disk but with no Plugin Name header (genuinely corrupt — needs operator attention)
These get picked up by the AF sync streams and surfaced on the wpdeploy dashboard so you can see which sites have been quietly recovering themselves and whether a particular release is failing more than it should.
3. Companion: post-update-silence alerts on wpdeploy (server side)
Wpdeploy's
report-healthroute now compares incomingplugin_versionagainst the row and writeslast_version_changed_at+previous_plugin_versionon change. TheSyncWatchdogcron then alerts if a site has reported a version change but not sent any heartbeat for 2+ hours since — likely a failed install. Emitssync_incidentsrows withkind=post_update_failureso the existing Telegram fan-out picks them up. Each version-change event alerts at most once.Files Changed
- Created:
inc/keepalive/auctionforge-keepalive.template.php,inc/keepalive/class-keepalive-installer.php - Modified:
inc/stats/class-stats-init.php(callAF_Keepalive_Installer::maybe_install()on every plugin load) - Modified:
auctionforge.php(Version 3.7.0.3 → 3.7.0.4)
Companion server-side changes (already deployed on wpdeploy.smoothbyteit.dev — not in this zip):
sitestable:last_version_changed_at TIMESTAMP NULL,previous_plugin_version VARCHAR(20) NULLapi.php/report-health route detects version changesSyncWatchdog::maybe_alert_post_update_failure()emits the new alert kind
Verification
1. Drop a 3.7.0.4 install on any site. Confirm
wp-content/mu-plugins/auctionforge-keepalive.phpexists post-load.2. Manually deactivate AF from the database (
DELETE FROM wp_options ...active_plugins...). Hit the homepage. AF reappears inactive_plugins;auctionforge_auto_reactivated_countincrements.3. Delete
mu-plugins/auctionforge-keepalive.php. Trigger AF load (any pageview). The file reappears.4. Bump KEEPALIVE_VERSION in the source template, ship a new release, observe the installed mu-plugin update on next AF load.
Operator notes
- Sites currently in the broken state (AF deactivated, no keepalive yet) are NOT auto-rescued by this release — they need a one-time manual reactivation in wp-admin OR a fresh AF install via wp-admin's Upload Plugin. After that, the keepalive is in place and future failures self-heal.
- The post-update-failure alert won't fire for upgrades that happened before this release (no
last_version_changed_atwas recorded). It activates from the first version change wpdeploy sees from each site after this update lands.
---
[3.7.0.3] — 2026-05-02
Fix: profile re-sync on login / profile-edit / register (no more empty names)
Why
The hourly profile sync uses a
user_registeredwatermark — once a user has been pushed once, the watermark advances past them and they're never re-pulled. That meant:1. Existing users whose first_name/last_name became populated AFTER their first sync stayed empty on wpdeploy forever.
2. BidSpirit-driven sites that don't write WP's standard
first_name/last_namefields shipped empty rows even though the canonical name was visible indisplay_name.The People view was showing
—for the name on rows that absolutely had a name available — just not where the sync handler was looking.Fixes (
inc/sync/class-profile-sync.php+inc/stats/class-stats-init.php)AF_Profile_Sync::push_for_user_id($user_id, $blocking=false)— new public method that builds a single user's profile row, normalises it, and POSTs to wpdeploy bypassing the watermark. Non-blocking by default (wp_remote_postwithblocking=false, timeout=2s) so login latency is unaffected.build_user_row($user_id)extracted as a reusable helper. Both the hourly batch and the on-demand push call it. Centralises role-filtering + display_name fallback + usermeta probing.display_namefallback. Whenwp_usermeta.first_name/last_nameare both empty (typical on BidSpirit-only sites),build_user_row()parsesdisplay_name("John Smith" → first=John, last=Smith) so we don't ship a row with a blank name when the data is sitting on the user record itself.- Three new action hooks registered in
class-stats-init.php::init(): wp_login→push_for_user_id($user->ID)— every login refreshes the rowprofile_update→ same — profile edits in wp-admin refreshuser_register→ same — new registrations get pushed instantly (instead of waiting up to 60 min for the next cron tick)
Files Changed
- Modified:
inc/sync/class-profile-sync.php(refactor + new method + display_name fallback) - Modified:
inc/stats/class-stats-init.php(three new action hooks) - Modified:
auctionforge.php(Version 3.7.0.2 → 3.7.0.3)
Verification
1. On a 3.7.0.3 site, find a user whose
wpdeploy.user_profiles.first_nameis empty:SELECT site_id, email, first_name FROM user_profiles WHERE email='something@example.com'2. Log in as that user (or have them log in).
3. Within ~2 seconds, re-query —
first_nameshould now be populated, either from the standard meta key OR parsed fromdisplay_name.4. The non-blocking POST means the user's login experience is unchanged — no spinner, no extra latency.
Operator note
Existing wpdeploy rows with empty
first_name/last_namewill refresh automatically as users log in or edit their profile. To force a one-shot re-walk of every user on a site (regardless of watermark), reset the watermark there:DELETE FROM wp_options WHERE option_name='auctionforge_profile_sync_watermark';Next hourly cron will re-pull every non-admin user with the new fallback applied.
---
[3.7.0.2] — 2026-05-02
Fix: sync-lots datetime mismatch + idle syncs now heartbeat
Why
Two issues surfaced in the wpdeploy Sync Health dashboard:
1. Every site's
sync-lotswas stuck onapi_error. The plugin sendslast_modifiedstraight fromwp_bp_meta_data.lastUpdate, which is a Unix epoch string ("1756919754"). wpdeploy'slots.last_modifiedcolumn is aDATETIME, so MariaDB rejects the insert withSQLSTATE[22007]: Incorrect datetime value. The handler recordsapi_errorand the watermark never advances, so every cron tick re-fails on the same batch.2. Sites with nothing to sync looked dead. When a sync handler had an empty batch (e.g. no non-admin users yet) it was returning early without POSTing anything. wpdeploy's
update_sync_health()only fires on a successful POST, sosites.sync_health_jsonstayed NULL and the dashboard showed grey dots — indistinguishable from a broken cron. WP-Cron was actually firing fine; the watchdog just couldn't tell.Fixes
inc/sync/class-lots-sync.php— newepoch_to_datetime()helper converts the BidSpirit epoch field to UTCY-m-d H:i:sbefore shipping. Idempotent: already-formatted datetimes pass through untouched, invalid values becomeNULL.inc/sync/class-sync-base.php::run()— always POST, even when the batch is empty. Empty payload is{records: []}and wpdeploy's existing handlers handle it gracefully (loop is skipped,update_sync_health()still fires withsynced=0). This makes the dashboard reflect cron liveness, not just data flow.
Files Changed
- Modified:
inc/sync/class-lots-sync.php - Modified:
inc/sync/class-sync-base.php - Modified:
auctionforge.php(Version 3.7.0.1 → 3.7.0.2)
Verification
1. On Clumber:
do_action('auctionforge_sync_lots')— confirm the previousauctionforge_last_sync-lots_status = api_errorflips tosuccess(N)and thatwpdeploy.lotsnow contains rows.2. On a site with no non-admin users:
do_action('auctionforge_sync_user_profile')— confirmauctionforge_last_sync-user-profile_status = idle(0)AND that wpdeploy's Sync Health page now shows a green dot for that cell.---
[3.7.0.1] — 2026-05-02
Fix: marketing data leaks WordPress admins into the people list
Why
After the 3.7.0.0 rollout the central
peopleview on wpdeploy was showing site administrators alongside real auction-house users — thesync-user-profilehandler read straight fromwp_userswith no role filter, so any account with administrator/editor/author/contributor/shop_manager capabilities was getting shipped as if it were a buyer. Marketing audiences must contain buyers, not staff.Fixes (
inc/sync/class-profile-sync.php)- The
read_batch()SQL now LEFT JOINs{$wpdb->usermeta}on the prefix-aware capabilities key ({$wpdb->prefix}capabilities) and filters out any user whose serialized capabilities meta_value containsadministrator,editor,author,contributor,shop_manager, orsuper_admin. Users withIS NULL(no roles registered) are still allowed through — those are typically subscribers/buyers on this fleet. - Watermark on
auctionforge_profile_sync_watermarkis unchanged; the next run after upgrade picks up the same batch with the new filter applied. Operationally the wpdeploy team also wiped the existing admin rows fromuser_profiles,user_interests,user_recent_activity,bids_wins, andpeopleto clear the leak server-side — total of 35 rows scrubbed.
Files Changed
- Modified:
inc/sync/class-profile-sync.php - Modified:
auctionforge.php(Version 3.7.0.0 → 3.7.0.1)
Verification on Clumber dev
1. Find a logged-in admin:
SELECT u.user_email FROM wp_users u JOIN wp_usermeta um ON um.user_id=u.ID AND um.meta_key='wp_capabilities' WHERE um.meta_value LIKE '%administrator%';2. Reset the watermark:
DELETE FROM wp_options WHERE option_name='auctionforge_profile_sync_watermark';3. Trigger sync:
do_action('auctionforge_sync_user_profile');4. On wpdeploy: confirm those admin emails do NOT appear in
user_profiles(SELECT * FROM user_profiles WHERE email='admin@…';returns zero rows).Privacy / scope
- No API contract changes. The wpdeploy
/api.php/sync-user-profileroute accepts the same payload shape; this is purely a source-side filter narrowing what gets sent.
---
[3.7.0.0] — 2026-05-02
Cross-site user data lake — full Phase 2 + Phase 3 build
Why
AuctionForge sites were exposing per-lot engagement (views, favourites, bids, wins) keyed only on the anonymous
af_vidlocalStorage hash, with no central aggregation. Marketing — even the "collect data now, send later" phase — needs a per-person view across the whole AF network: name + phone + postcode + country + IP + device fingerprint + the keywords they engage with + the bids they place + the lots they win, all rolled up across every site they've used. This release wires every piece needed for that, and keeps it sustainable: per-site aggregates rather than raw event firehose, watermarked syncs with retry, 14/30-day site-side retention, watchdog + Telegram alerts for dead streams.See
/root/.claude/plans/i-want-to-add-synthetic-goose.mdfor the full architecture.New tables (idempotent dbDelta on the existing
plugins_loadedmigration path)wp_af_stats_lot_keywords— per-lot keyword cache. Title + tags + author tokenized (lowercase → drop stop-words → drop ≤2-char → drop pure-digit), one row per (post_id, keyword). Populated onsave_post_lot.wp_af_user_interests— running tally per(user_email, dimension, dimension_value)where dimension ∈keyword | category | author | price_band. UPSERT-keyed so increments are atomic. Bounded by users × distinct interests (typically a few dozen rows per user).wp_af_user_recent_activity— capped per-user activity log (last 50 events per email). Seeds the drill-down timeline on the wpdeploy person view.wp_af_bid_events— bid + win events (auto-created by the bids sync handler). Drained and shipped to wpdeploy hourly.synced_atcolumns added towp_af_stats_pageviews,wp_af_stats_sessions,wp_af_stats_searches,wp_af_stats_outbound. Powers the durable sync-and-purge lifecycle.af_stats_db_versionbumped 2 → 3. The existingAF_Stats_Init::maybe_create_tables()picks up the new tables on the next admin page load after auto-update.
New helper classes
AF_Keyword_Extractor(inc/stats/class-keyword-extractor.php) — pure tokenizer + cache writer + read-through helper. Hookssave_post_lotto refresh on lot changes. Stop-words tunable viaapply_filters('af_keyword_stop_words', ...).AF_User_Interests(inc/stats/class-user-interests.php) —record_view / record_favorite / record_bid / record_win. All idempotent UPSERTs. CallsAF_Stats_Tracker::should_skip()first so admins/bots never pollute interest profiles.AF_Sync_Base(inc/sync/class-sync-base.php) — abstract durability backbone. Readssynced_at IS NULLbatches, POSTs, marks rows synced only on a confirmed 200, retries on next cron run if the POST fails. Idempotent UNIQUE keys on the wpdeploy side mean retries never duplicate.AF_Profile_Sync/AF_Interests_Sync/AF_Activity_Sync/AF_Lots_Sync/AF_Bids_Sync— five concrete sync streams.AF_Data_Purge(inc/maintenance/class-data-purge.php) — daily cron: 14-day floor on synced rows, 30-day hard cap with CRITICAL alert if any unsynced row hits the cap (which would mean wpdeploy has been unreachable for a month).
New cron schedules (auto-registered on plugins_loaded if
auctionforge_update_server_url+_api_keyare configured)| Hook | Schedule | Endpoint |
|---|---|---|
|
auctionforge_sync_user_profile| hourly |POST /api.php/sync-user-profile||
auctionforge_sync_user_interests| hourly |POST /api.php/sync-user-interests||
auctionforge_sync_user_activity| hourly |POST /api.php/sync-user-activity||
auctionforge_sync_lots| every 10 min |POST /api.php/sync-lots||
auctionforge_sync_bids_wins| hourly |POST /api.php/sync-bids-wins||
auctionforge_purge_synced_data| daily | (purge cron — local) |All sync handlers are watermarked or
synced_at-gated; cron mid-run failure is harmless because the next run picks up the same rows.Hooks fired
af_stats_pageview_recorded($url, $email, $visitor_hash)— fires insideAF_Stats_Ajax::handle_track()after a logged-in pageview is recorded. Default listener resolves URL → lot post →AF_User_Interests::record_view().af_stats_lot_favorited($email, $post_id)— fires from the existinglot_analytics_record_favoriteAJAX handler when a watchlist add happens. Default listener callsrecord_favorite().
Server-side companion (wpdeploy)
This release is paired with wpdeploy changes (handled out-of-band; not in the plugin zip):
- 5 new API routes matching the sync streams above. All return
synced+ watermark metadata so the plugin can advance / mark rows synced. update_sync_health()helper in wpdeploy — every successful sync POST writes(stream, last_seen_at, last_synced_count, state)intosites.sync_health_json.SyncWatchdog— 5-minute cron on wpdeploy that scans every (site × stream) cell and runs anok → overdue → gone → recovering → okstate machine. Emits alerts via the existingsync_incidentsTelegram fan-out.- People section in the wpdeploy admin —
?tab=people(cross-site rollup with top keywords / lifetime spend),?tab=person&email=...(drill-down with timeline + bids),?tab=people-export(Google Customer Match + Meta Custom Audience CSV with sha256 hashing per spec). ?tab=sync-health— site × stream traffic-light grid showing every sync's state.
Files Changed
- Created:
inc/stats/class-keyword-extractor.php,inc/stats/class-user-interests.php,inc/stats/stop-words.php - Created:
inc/sync/class-sync-base.php,inc/sync/class-profile-sync.php,inc/sync/class-interests-sync.php,inc/sync/class-activity-sync.php,inc/sync/class-lots-sync.php,inc/sync/class-bids-sync.php - Created:
inc/maintenance/class-data-purge.php - Modified:
inc/stats/class-stats-database.php(DB_VERSION = 3, new dbDelta calls, synced_at column adds) - Modified:
inc/stats/class-stats-init.php(require new classes, register sync crons, wireaf_stats_pageview_recordedandaf_stats_lot_favoritedlisteners) - Modified:
inc/stats/class-stats-ajax.php(fireaf_stats_pageview_recordedafter pageview record; fireaf_stats_lot_favoritedon watchlist add) - Modified:
auctionforge.php(Version: 3.6.4.0 → 3.7.0.0)
Verification on Clumber dev
1. After auto-update + first wp-admin page load:
wp_af_stats_lot_keywords,wp_af_user_interests,wp_af_user_recent_activityall exist;af_stats_db_version = 3.2. Save a test lot titled
"Pair of Victorian silver candlesticks by Mappin & Webb"→wp_af_stats_lot_keywordshas rows forvictorian, silver, candlesticks, mappin, webb(and notpair, of, by).3. Log in as throwaway test user, view 3 of those lots →
wp_af_user_interestsshows(test@…, keyword, 'victorian', view_count=3).4. Wait one hourly cron, confirm
wpdeploy.user_interestsmirror via the wpdeploy admin →?tab=people→ search for the test email.5. Confirm
wpdeploy.sites.sync_health_jsonhasuser-interests.state = 'ok'for the Clumber site.6. Pause the cron, wait 2h, watch the watchdog flip the cell to
overdueand emit a Telegram alert.Privacy / scope
- Admins and bots are filtered out at write time via
AF_Stats_Tracker::should_skip(). - Email is normalized lowercase + trim before storage; phone normalized to E.164 (UK-aware) on the sync side.
- No outbound activation yet — wpdeploy stores everything but doesn't send anything to anyone. Marketing send mechanics (consent flag, suppression list, sender) explicitly deferred.
---
[3.6.4.0] — 2026-05-02
Identity stitching: visitor_hash → user_email
Why
The
af_stats_*tables (pageviews,sessions,searches,outbound) and the lot-engagement tables (af_lot_analytics,af_lot_shares) currently store activity keyed only on the anonymousaf_vidlocalStorage hash — there is no link from any browsing event to the user's email even when they're logged in. Without that link, the central wpdeploy server can never aggregate behavioural data on a per-person basis, which is the prerequisite for the cross-site user-data lake being built on wpdeploy (see/root/.claude/plans/i-want-to-add-synthetic-goose.mdPhase 1).This release adds the bridge: every authenticated tracker hit records a
(visitor_hash, user_email)pair into a new table. From here on, anonymous browsing can be resolved to an email via JOIN for any session the user was logged in.Changes
- New table
wp_af_stats_visitor_emails—(visitor_hash, user_email, ip_address, first_seen, last_seen)withUNIQUE(visitor_hash, user_email)+ index onuser_email. Created viadbDeltainside the existingAF_Stats_Database::create_tables()so it ships through the standardplugins_loadedmigration path — no manual reactivation needed after auto-update. af_stats_db_versionbumped 1 → 2.AF_Stats_Init::maybe_create_tables()now compares against the newAF_Stats_Database::DB_VERSIONconstant rather than a hard-coded< 1, so future schema bumps (Phase 2 onwards) just require constant edits + new dbDelta calls.- Identity record on every authenticated tracker hit.
AF_Stats_Ajax::handle_track()now callsAF_Stats_Visitor_Email_Map::record($visitor_hash, $email, $ip)wheneveris_user_logged_in()is true. Trust boundary: the email is read server-side fromwp_get_current_user()— clients cannot assert who they are. - Defensive table-exists guard. The new helper short-circuits silently if the migration hasn't run yet on a given site (race window on the very first request after auto-update); the next request finds the table and proceeds. No fatals, no missing rows.
- Email normalised at write time — lowercase + trim +
is_email()validation before storage. Marketing audience match-rates downstream depend on consistent casing.
Files Changed
- Created:
inc/stats/class-visitor-email-map.php - Modified:
inc/stats/class-stats-database.php(DB_VERSION constant; new table; drop_tables list) - Modified:
inc/stats/class-stats-init.php(require new helper; migration check uses constant) - Modified:
inc/stats/class-stats-ajax.php(record pair inhandle_track) - Modified:
auctionforge.php(Version header bump)
Verification on Clumber dev
1. After auto-update, load any
wp-admin/*page once →wp_af_stats_visitor_emailsexists,af_stats_db_version = 2.2. Log in as a test user, browse 5 lots → exactly one row in
wp_af_stats_visitor_emailsfor that(visitor_hash, email)pair, withlast_seenupdating on each hit.3.
SELECT email FROM wp_af_stats_visitor_emails WHERE visitor_hash IN (SELECT visitor_hash FROM wp_af_stats_pageviews WHERE created_at > NOW() - INTERVAL 1 HOUR)returns the test email — proving the JOIN works.Privacy / scope
- This change writes a
(visitor_hash, email)pair to a single new table on the AF site. Nothing is sent to wpdeploy yet — the sync stream lands in Phase 2. - Anonymous (logged-out) browsing is unaffected: no row is created until the user authenticates.
- Bots are still skipped via
AF_Stats_Tracker::is_bot()before any tracking writes.
---
[3.6.3.1] — 2026-05-01
Fix: New lots never processed + Live console improvements
Why
When BidSpirit adds new lots to an auction (e.g. items 683-692), the sync pipeline correctly staged all 709 lots into
import_historybut the InsertLotsBS processing loop exited after the first batch of 500 unchanged lots, never reaching the genuinely new lots at the tail of the queue. This caused new lots to remain permanently stuck in staging — synced but never created as WordPress posts.Separately, the admin Live Console was replaying the entire log history from the beginning on every page load, and showed long silent gaps during API calls with no indication of what the worker was doing.
Fixes
- InsertLotsBS loop break condition — The stage 5 insert loop in
CatalogSyncWorker::process()andprocessDayEnded()previously broke whenupdated lots === 0, even if the batch had cleared hundreds of unchanged ("unupdated") lots from the queue. New lots with higher IDs were never reached. Now breaks only when bothupdated lotsandunupdated lotsare 0, meaning the staging queue is truly empty. - Live Console starts from current position —
consoleSinceIdwas hardcoded to0, causing the console to page through the entireaf_sync_logtable (50 rows at a time) before reaching real-time entries. Now initializes toSyncLogger::getLatestId()so only entries created after page load appear. queueIsActivedeclaration order — Variable was declared after functions that referenced it, causing the console to always start at the slow 3s polling rate even when a worker was active. Moved declaration before first use.- Progress logging during API calls —
LotList::auctionProcessing()made 2-3 BidSpirit API calls with zeroSyncLoggerentries, creating long silent gaps in the console. Added log entries for API fetch start, response received (with duration), data staged, and API errors. - Per-auction progress in bulk runs —
LotList::run()now logsProcessing auction X/Y: {id}for each auction in the bulk loop, and logs skipped auctions. processDayEndedinsert loop logging — Added batch progress logging and timeout guard matching theprocess()method pattern. Previously this loop was completely silent.
Files Changed
- Modified:
inc/sync/CatalogSyncWorker.php,inc/import/LotList.php,admin/view/sync-status.php
---
[3.6.3.0] — 2026-05-01
Public Auctions API — Token Authentication
Why
The
/wp-json/auctionforge/v1/public/auctionsendpoint added in v3.6.2.9 was publicly accessible. Since auction data should only be served to authorized aggregator sites, the endpoint now requires a valid auth token.Changes
- Token verification — The
PublicAuctionsREST endpoint now validates anX-AF-Tokenheader (or?token=query parameter) against the site's existing Webhook auth token from AuctionForge settings. - Returns
401 Unauthorizedfor missing/invalid tokens and403 Forbiddenif no auth token is configured on the site. - Uses
hash_equals()for timing-safe comparison.
Files Changed
- Modified:
auctionforge.php,inc/api/PublicAuctions.php
---
[3.6.2.9] — 2026-05-01
Public Auctions REST API Endpoint
Features
- New REST endpoint
GET /wp-json/auctionforge/v1/public/auctions— Exposes auction list data (title, date, image, state, catalog link) for consumption by the AuctionForge Hub plugin on parent/main sites. - Parameters:
type(upcoming or past, default: upcoming),limit(max results, default: 50). - Handles multi-day auctions with correct part numbers and catalog links.
- Returns auction metadata including
auction_id,source_site, andday_indexfor deduplication.
Files Changed
- Modified:
auctionforge.php,inc/coreIncludes.php - Created:
inc/api/PublicAuctions.php
---
[3.6.2.8] — 2026-04-30
Suppress alerts for transient retry conditions
Why
The "BidSpirit API returned 0 lots — catalog may not be ready yet" message is logged when the BidSpirit webhook fires before the auction catalog is fully published. The safety cron retries the job automatically and it usually succeeds on the next attempt — there's no operator action required, so a Telegram alert is just noise.
Fix
- New private helper
SyncLogger::isSuppressedFromAlerts($message, $context)matches the message against a substring allowlist of known-transient errors. When matched, the row is still inserted intoaf_sync_log(so the in-app sync console still shows the retry chain) but theauctionforge_sync_error_loggedfan-out action does NOT fire — wpdeploy and Telegram stay quiet. - Default suppression substrings:
"BidSpirit API returned 0 lots","catalog may not be ready yet". - Extendable via the new
auctionforge_sync_alert_suppress_patternsfilter — themes/MU plugins can add their own substrings.
Files Changed
- Modified:
auctionforge.php,inc/sync/SyncLogger.php
---
[3.6.2.7] — 2026-04-30
Typo fix
- Settings → Connections tab: the placeholder/help text under the Server field showed
https://my-accaunt.bidspirit.com/(extra "a"). Now readshttps://my-account.bidspirit.com/.
Files Changed
- Modified:
auctionforge.php,inc/controllers/Settings.php
---
[3.6.2.6] — 2026-04-30
Fix stale
plugin_versionin reportsWhy
Sites were reporting their old version to wpdeploy long after they'd been upgraded — e.g. Lonsdale Auctioneers ran v3.6.1.1 but kept telling wpdeploy it was on v2.9.6. Root cause: the constant
AUCTIONFORGE_VERSIONis read from the plugin file'sVersion:header *once at plugin load*, then frozen into$this->current_versionon the auto-updater instance. After a plugin upgrade replaces the file on disk, existing PHP-FPM workers keep using the cached constant value until they're recycled, so every report from those workers carries the old version.Fix
- New helper
AuctionForge_Auto_Updater::get_live_version()reads the version directly from the plugin file's header on each call (viaget_file_data()— uncached). report_health,push_sync_error_immediate, andretry_sync_errorsnow sendget_live_version()instead of the cached constant.- The pre-existing iteration through active plugins inside
report_healthalready usedget_plugin_data()per plugin, so secondary plugin entries were already accurate; only the top-levelplugin_versionfield was stale.
Files Changed
- Modified:
auctionforge.php,inc/class-auto-updater.php
---
[3.6.2.5] — 2026-04-30
Real diagnostics for plugin self-updates
Why
The wpdeploy
update_queuetable had a 46% historical failure rate, but every single failure row stored the literal string"Installation failed"— collapsing every failure mode into one opaque error with no diagnostic value. Root cause: theinstall_update()method in both clients (AF auto-updater and wpd-client) treatedPlugin_Upgrader::upgrade()as a boolean, throwing awayWP_Errorobjects and skin-emitted error messages.Fixes (
inc/class-auto-updater.phpinstall_update())- Refreshes the
update_pluginstransient before invoking the upgrader. The upgrader reads from this transient to know what version to download; if WP hasn't checked recently, the upgrader silently returns false (looking like a failure even though there's a real update queued at wpdeploy). - Distinguishes
WP_Error,false/null, and success.WP_Errorwas previously treated as truthy → reported as "completed" even on failure. Now extracts the error code and message. - Reads
Automatic_Upgrader_Skin::get_errors()to surface the real upgrader-emitted error messages. - Reads
$upgrader->resultwhich holds the finalWP_Errorfor some failure paths. - Captures PHP errors/warnings emitted during the upgrade (file-move issues, etc.) via a temporary
set_error_handler. - Detects "no update in transient" as a distinct failure cause and labels it explicitly so we know it's a transient-cache problem, not an actual install failure.
- Truncates the combined diagnostic to 1000 chars before sending.
The same fix is applied to
wpd-client.php(the WPD client plugin shipped fromclient-plugin/wpd-client.phpon the wpdeploy server).Files Changed
- Modified:
auctionforge.php,inc/class-auto-updater.php
---
[3.6.2.4] — 2026-04-30
Bulk-sync worker dispatch fix
Fixes
- The HTTP-loopback worker (
auctionforge_rest_sync_workerinauctionforge.php) had its own switch statement for job-type dispatch, distinct from the one incrontasks/syncWorker.php. The newfull_sync_upcomingandfull_sync_pastjob types were only added to the CLI worker, so the loopback path produced "Unknown job type" errors. Both switches now route those types toBulkSyncWorker::process. inc/coreIncludes.phpnowrequire_oncesBulkSyncWorker.phpso the class is available wherever sync code runs.
Files Changed
- Modified:
auctionforge.php,inc/coreIncludes.php
---
[3.6.2.3] — 2026-04-30
Fixes for end-to-end Telegram round-trip
Fixes
verify_api_keyreads the option fresh on every call (hash_equalsagainstget_option('auctionforge_update_api_key')) instead of relying on the cached$this->api_keyfrom constructor time. Different FPM workers can hold different cached values when the option drifts (e.g. via auto-heal collisions), which previously produced intermittent 401s on REST endpoints.- New REST endpoint
POST /wp-json/auctionforge/v1/sync/version— wraps the existingtrigger-installflow with a JSON response (always HTTP 200 withsuccessflag). The original endpoint returnedWP_Error('no_update', …, status: 404)when the plugin was already on the latest version, which nginx'serror_page 404directive then clobbered with a static HTML 404 page on hosts using aaPanel/BTWAF. Keeping the URL under/sync/*matches the pattern that's already proven to pass through host WAFs.
Files Changed
- Modified:
auctionforge.php,inc/class-auto-updater.php
---
[3.6.2.2] — 2026-04-29
Catalog-sync kind disambiguation
Fix
catalog_syncjobs target a single auction that may be either active or archived. Until now their alerts were always classified askind=upcoming. The classifier now resolves the auction'sauction_stateterm meta and routes:ARCHIVED/ENDED/POST_AUCTION→kind=past→ Kill + Full Past buttons- anything else (or unresolvable) →
kind=upcoming→ Kill + Full Upcoming buttons
Files Changed
- Modified:
auctionforge.php,inc/class-auto-updater.php
---
[3.6.2.1] — 2026-04-29
Telegram Sync Monitoring follow-ups
Features
- Context-aware alert buttons. Each Telegram alert now shows the action set most relevant to the failing sync: upcoming-sync errors get Kill + Full Upcoming, past-sync errors get Kill + Full Past, everything else gets Kill only. Button choice is driven by a new
kindfield classified at log-write time from the queue'sjob_type. - Plugin version in alerts + Update button. Each push now includes the live
plugin_version. wpdeploy compares it to the latestis_stable=1row in itsversionstable and only renders an Update plugin button when the site is behind. Tapping Update calls the existingPOST /wp-json/auctionforge/v1/trigger-installendpoint to force the upgrade.
Architecture
- New private helper
AuctionForge_Auto_Updater::classify_error_kind($jobId)looks up the job'sjob_typeand maps it to'upcoming'/'past'/'other'. Used by both the immediate push and the 1-min retry cron. - Outbound payloads now include
plugin_versionat the top level; wpdeploy refreshessites.plugin_versionon every/sync-errorsPOST.
Files Changed
- Modified:
auctionforge.php,inc/class-auto-updater.php
---
[3.6.2.0] — 2026-04-29
Telegram Sync Monitoring & Remote Control
Features
- Instant Telegram alerts on sync errors. Any
level='error'row written toaf_sync_logis pushed (fire-and-forget, non-blocking) to wpdeploy, which fans it out to a configured Telegram group with inline-keyboard action buttons (Kill / Full Upcoming / Full Past / Acknowledge). - Remote command surface. Any group admin can tap a button to:
- Kill sync — flips DB flags via
SyncQueue::cancelAll(), then SIGTERMs every active worker; a 5-second watchdog escalates to SIGKILL for any survivor. - Full sync upcoming — full re-import of every active auction and its lots (queued, observable, killable). Replaces the
re-sync?do=importBidSpiritUpcomingflow with a queued equivalent. - Full sync past — same, for archived auctions.
- Safety-net retry cron (
auctionforge_retry_sync_errors, every minute) re-pushes recent error rows. wpdeploy dedupes viaUNIQUE(site_id, af_log_id)so duplicates are silent.
Architecture
SyncLogger::log()now firesdo_action('auctionforge_sync_error_logged', …)onlevel='error'so any handler can react. The auto-updater listener does a 2 s non-blocking POST to/api.php/sync-errors.- New REST endpoint
POST /wp-json/auctionforge/v1/sync/cancel-all(X-API-Key auth) — runsSyncQueue::cancelAll()+ SIGTERM + watchdog. Logs every action throughSyncLogger. POST /sync/startextended with amodeparameter (upcomingdefault,pastfor archived). Bulk re-sync is now a queued job, not a synchronous block.- New job types
full_sync_upcomingandfull_sync_pastonSyncQueue, dispatched to a newBulkSyncWorkerthat wraps the existingAuctionList::init()+LotList::init($upcoming)pipeline. syncWorker.phpinstalls a SIGTERM handler that flips the in-flight job tofailedwith a "Killed by admin (SIGTERM, cleanup OK)" marker and closes the DB cleanly before exiting. Watchdog escalates to SIGKILL after 5 s grace.LotList::auctionProcessing()now heartbeats the active bulk-sync job between auctions, preventing the safety cron from auto-failing long bulk runs as stale (the 600 s threshold is unchanged).
Files Changed
- Modified:
auctionforge.php,inc/sync/SyncLogger.php,inc/sync/SyncQueue.php,inc/class-auto-updater.php,crontasks/syncWorker.php,inc/import/LotList.php - Created:
inc/sync/BulkSyncWorker.php
---
[3.6.1.6] — 2026-04-29
High-Value Lot Modes for
[bp_lot_list]Features
high_value_pastmode — Displays past auction lots ordered by their catalog estimate (estimatedPriceInt), highest first. Useful for "Top Lots" or "Highlights" sections.high_value_soldmode — Displays past sold lots ordered by their actual sold price (soldBid), highest first. Only includes genuinely sold lots (soldBid > 0) and reuses the same false-positive guard asrandom_pastto skip lots wheresoldBidwas carried over fromstartPricewithout real bidding activity.- Admin documentation updated — The Shortcodes reference page in WP Admin now lists both new modes in the
modeattribute description and includes example shortcode usage.
Architecture
- New constants
MODE_HIGH_VALUE_PASTandMODE_HIGH_VALUE_SOLDonLotsWidget. - New method
LotsWidget::getLotListHighValue($mode, $limit)builds the query, applies the past-auction tax filter, setsbp_orderbyto the relevant meta field withDESCorder, and (for the sold variant) filters out unsold-but-stale lots in PHP. - New filter hook
bp_lot_list_high_value_args_filterfor downstream customization of the WP_Query args.
Files Changed
- Modified:
inc/widgets/LotsWidget.php,inc/controllers/ShortcodesPage.php
---
[3.6.0.18] — 2026-04-25
Brevo SMS Notifications Integration
Features
- Transactional SMS via Brevo API — The plugin now sends text message alerts through the Brevo transactional SMS service, running alongside existing Firebase push notifications.
- Four Notification Types:
- New Auction Published — Broadcast SMS to all opted-in subscribers when an auction is published.
- Auction Starting Soon — Targeted SMS to users registered for an auction when it is about to start.
- Favorited Item Live Soon — Targeted SMS to users who favorited a lot when it is approaching in the auction.
- Outbid Notice — SMS sent when a user's leading bid is surpassed, with a 5-minute per-item cooldown to prevent spam.
- SMS Subscriber Database — New
af_sms_subscriberstable stores user phone numbers, country codes, and per-notification-type opt-in preferences (GDPR-ready explicit consent). - Admin Settings Tab — New "SMS Notifications" tab in Settings with:
- Brevo API Key input
- SMS Sender Name (11 char max)
- Master enable/disable toggle
- Per-notification-type on/off switches
- Test SMS widget with phone input and send button
- Live subscriber count display
- Profile SMS Preferences — Users can opt into SMS notifications directly from their profile page with phone number entry and granular notification type selection.
Architecture
- BrevoSMS Service (
inc/services/BrevoSMS.php) — cURL-based API wrapper with broadcast, targeted, and single-send methods, message builders with 160-char limit awareness, rate limiting, and comprehensive error logging. - SMSSubscriber Model (
inc/model/SMSSubscriber.php) — CRUD operations, email-to-phone resolution, opt-in filtering, and upsert logic. - Webhook Integration — SMS dispatch hooks added to
AuctionsAPI.phpmethods:leading_bid_surpassed(),item_live_soon(),auction_starts_soon(), andauctionPublishedPush().
AJAX Handlers
auctionforge_sms_save— Save SMS preferences from profile pageauctionforge_sms_load— Load SMS preferences for profile pageauctionforge_sms_test— Admin-only test SMS endpoint
Database
- New table:
af_sms_subscribers— Phone numbers, country codes, per-notification opt-ins, timestamps
Files Changed
- Modified:
auctionforge.php,inc/coreIncludes.php,inc/controllers/AuctionsAPI.php,inc/controllers/Settings.php,admin/view/settings.php,templates/parts/profile-templates.php - Created:
inc/services/BrevoSMS.php,inc/model/SMSSubscriber.php
---
[3.6.0.7] — 2026-04-14
Hotfix
Fixes
- Namespace resolution — Fixed fatal error in
wp_footercommission label hook caused by unqualifiedSettingsHelperandSettingsclass references. Now uses fully qualified namespaces.
Files Changed
- Modified:
auctionforge.php
---
[3.6.0.6] — 2026-04-14
Commission Label Override Fix
Fixes
- Theme template override compatibility — Moved the commission label JS override from the
single-lot.phptemplate intoauctionforge.phpviawp_footerhook (priority 99). Sites with theme-level template overrides (e.g.themes/*/auctionforge/single-lot.php) were not picking up the inline script. Thewp_footerapproach works universally on all single lot pages.
Files Changed
- Modified:
auctionforge.php,templates/single-lot.php
---
[3.6.0.5] — 2026-04-14
Commission Label Override
Features
- Commission Label Setting — New dropdown in Settings → Appearance allowing admins to choose between "Buyer's Premium" (default) and "Auction House Commission" as the label displayed on lot pages. This overrides the Bidspirit JS client's default label using a MutationObserver that catches asynchronously injected text.
Files Changed
- Modified:
inc/controllers/Settings.php,templates/single-lot.php
---
[3.6.0.4] — 2026-04-12
Auction Approval Modal Redesign
Changes
- Removed BidSpirit Terms of Use — The generic BidSpirit "Terms of Use" section that appeared at the top of the non-credit-card approval modal has been removed. The modal now shows only the auction house's own legal agreements managed within the plugin.
- Renamed Modal Title — Changed "Terms of conditions" to "Terms & Conditions".
- Larger Scroll Area — The Terms & Conditions scroll box is now 350px tall (up from 200px) for easier reading.
- Proportional Section Heights — Refund & Return Policy and Chargeback Waiver sections use a shorter 260px scroll box to visually distinguish them from the primary Terms & Conditions.
Files Changed
- Modified:
templates/js-chunks/approval-info.php,assets/js/app.js
---
[3.6.0.2] — 2026-04-10
Webhook Token Generator
Features
- Token Generator Widget — Added a 16-character random token generator directly below the "Webhook auth token" field on the Settings page. Includes a "Generate Token" button and a clipboard copy icon with visual feedback.
Files Changed
- Modified:
inc/controllers/Settings.php
---
[3.6.0.1] — 2026-04-10
Patch
Changes
- Version bump.
---
[3.6.0.0] — 2026-04-10
Legal Agreements for Auction Approval
Features
- Terms & Conditions — A mandatory, scrollable Terms & Conditions document is now displayed during the auction approval process. Bidders must scroll to the bottom and check an agreement box before their approval request is submitted. Always enabled.
- Refund & Return Policy — An optional, scrollable Refund & Return Policy can be enabled in Settings. When enabled, bidders must read and accept it during auction approval.
- Chargeback Waiver — An optional, scrollable Chargeback Waiver can be enabled in Settings. When enabled, bidders must read and accept it during auction approval.
- Admin Management — New "Legal Agreements" page under the Bidspirit admin menu with tabbed TinyMCE editors for each agreement type. Includes automatic version numbering (incremented on content change) and full version history.
- Consent Logging — Every agreement acceptance is logged to a dedicated database table (
af_user_agreement_log) with the agreement type, version, user email, IP address, user agent, auction ID, and timestamp. - User Tracking Integration — Agreement events (
terms_agreement,refund_agreement,chargeback_waiver) are also recorded in the existing IP tracking system alongside registration, login, and bid events. - Placeholder Content — Default sample content is seeded on plugin activation for all three agreement types.
Settings Added
- Enable Refund & Return Policy — Toggle to require bidders to accept the refund policy during auction approval.
- Enable Chargeback Waiver — Toggle to require bidders to accept the chargeback waiver during auction approval.
Database
- New table:
af_legal_agreements— Current active agreement content per type - New table:
af_legal_agreement_versions— Version history archive - New table:
af_user_agreement_log— User consent records
Files Changed
- Modified:
auctionforge.php,inc/controllers/Settings.php,inc/controllers/BidspiritViews.php,inc/ip-logger.php,templates/js-chunks/approval-info.php,assets/js/app.js - Created:
inc/legal/class-legal-agreements.php,admin/view/legal-agreements.php
---
[3.5.0.6] — 2026-04-08
Bid Event Tracking
Features
- Bid Tracking — All successful bids (regular, catalog, pre-sale buyout, post-sale purchase) now fire
afLogIP("bid", bidspiritUser)to capture the bidder's full identity in the user tracking table. - Whitelist Update — Added
bidto the allowedevent_typevalues in both the local plugin and the central WPDeploy API.
---
[3.5.0.5] — 2026-04-08
Self-Healing Database Schema
Features
- Auto-Migration — The plugin now auto-detects and adds any missing tracking table columns on version upgrade, ensuring sites with older schemas seamlessly migrate without manual SQL.
---
[3.5.0.4] — 2026-04-08
API Key Auto-Healing
Features
- Seamless Self-Registration — The WordPress plugin now autonomously regenerates and saves a fresh API Key whenever WPDeploy rejects a payload with an
api_key_collisionerror. This guarantees zero-downtime security handovers when developers clone instances to proxy/staging servers.
---
[3.5.0.3] — 2026-04-08
API Key Collision Defense
Features
- 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_collisionerrors, directly instructing developers to update cloned keys.
---
[3.5.0.2] — 2026-04-08
Modal Trigger Hotfix
Fixes
- Restructured internal UI rendering priority to gracefully deploy the inline Modal triggers inside custom IP log view without colliding with cached
z-indexstacks.
---
[3.5.0.1] — 2026-04-08
Hotfix
Fixes
- Timed Auction Badge Visibility — Fixed a strict type-matching bug in the main
auction_list.phpcore file that incorrectly hid the "Timed Auction" badge overlay from valid timed/online auctions on the main upcoming/archive views. The badge now displays properly across all manual and Bidspirit-synced objects when toggled on.
Files Changed
- Modified:
templates/main/auction_list.php
---
[3.2.9.1] — 2026-03-30
Timed Auction Display Enhancements
Features
- Timed Auction Countdown Text Toggle — Added a WP-Admin setting "Change text to 'Auction will close in'" that conditionally changes the countdown label for timed/online auctions on single lot pages.
- Shortcode Text Toggle Support — Extended the new countdown text logic to the
bp_upcoming_wideshortcodes so "Live bidding starts in:" successfully transitions to "Auction will close in:" for timed auctions.
Files Changed
- Modified:
inc/controllers/Settings.php,templates/single-lot.php,templates/shortcodes/upcoming-auction-wide.php,templates/shortcodes/upcoming-auction-wide-manual.php
---
[3.2.9.0] — 2026-03-29
Billing & Invoices Polish
Fixes
- Profile Invoice ID Tracking — Prevented internal auction codes (e.g.
002orai4) from breaking into the clean hyphenated titles inside theprofile-templates.phpview. - Dynamic Payment Statuses — Replaced Bidspirit's default/cached
NOT PAIDHTML payloads by wiring thedompdfgenerator to directly respect the current$b.statusstring from the API (resolving instances where a paid invoice still printed "NOT PAID" atop the document). - Payment Instructions Conditional — Automatically hide the "Payment Instructions" block from the PDF footer when an invoice is fully paid.
- Improved Nomenclature — Changed "Invoice No:" to "Bidder No:" on document output to prevent confusion with static invoice ledger IDs.
---
[3.2.6.0] — 2026-03-28
Multi-Day Auction Lot Filtering Fix
Fixes
- Day 2+ showing lots from Day 1 in multi-day auctions — The
itemIndexcolumn inbp_meta_dataisvarchar(55), but the day-range filter inBidspiritQuery::bp_query_where()was comparing it as a string. With string comparison, lot numbers like'11','101'–'145'incorrectly fell between'1001'and'1450', causing Day 1 lots to leak into Day 2 results. Fixed by usingCAST(bpMeta.itemIndex AS UNSIGNED)for numeric comparison andintval()on the PHP-side boundary values. Letter lots (e.g.14A,1025A) are handled correctly —CASTstrips the suffix, keeping them grouped with their base lot number.
Files Changed
- Modified:
inc/controllers/BidspiritQuery.php
---
[3.2.5.9] — 2026-03-27
Catalog Page Fix
Fixes
- Duplicate preview hours on catalog pages — The
displayHoursfield was rendered twice: once via thebp_after_description_auctionhook inBidspiritViews.phpand once inline in the auction template. Removed the hook-based rendering to eliminate the duplication.
Files Changed
- Modified:
inc/controllers/BidspiritViews.php,templates/main/auction.php
---
[3.2.5] — 2026-03-19
Sync Reliability & Stuck Lot Prevention
Fixes
- CATALOG_PUBLISHED webhook now triggers catalog sync — Previously only sent push notifications without syncing lots. When the earlier AUCTION_CATALOG_UPDATED fired before the catalog was ready on BidSpirit, lots were never imported. CATALOG_PUBLISHED now calls
auctionCatalogUpdated()to trigger a full catalog sync when the catalog is actually available. - 0-lot API results now fail instead of silently succeeding — When BidSpirit API returns 0 lots (catalog not yet ready), the sync job now fails with an explicit error message, allowing the next webhook to create a fresh retry job.
- Expanded CDN allowlist in pre_http_request filter — The HTTP filter during bulk post insertion now allows all
*.bidspirit.comsubdomains and BidSpirit image CDNs (fastly.net,cloudfront.net). Previously onlybidspirit.comandwww.bidspirit.comwere allowed, blocking image downloads during sync and causing worker hangs. - InsertLotsBS timeout guard — Stage 5 (InsertLotsBS processing loop) now has a 180-second timeout and logs progress every 2 batches. Prevents indefinite hangs that previously required manual force-kill.
- fixResult() no longer marks lots as done when postId=0 — When
lotProcessing()fails to create a WP post, the staging row now keepssyncFinished=0so the lot is retried on the next sync pass, instead of being permanently marked as complete with no actual post. - lotProcessing() logs error on missing auction term — Previously returned 0 silently when
Auction::findAuctionById()failed. Now logs an explicit error that feeds intofixResult()to keep the lot retryable. - Hourly orphan detection in safety cron — New step in
syncSafety.phpdetects lot posts that exist inbp_meta_databut are missing their auction taxonomy assignment (caused by workers killed mid-batch) and auto-repairs them withwp_set_object_terms().
Files Changed
- Modified:
inc/controllers/AuctionsAPI.php,inc/sync/CatalogSyncWorker.php,inc/abs/InsertLotsAbstract.php,inc/import/InsertLotsBS.php,crontasks/syncSafety.php
---
[3.2.4] — 2026-03-18
Sync Worker Hang Fix
Fixes
- Sync workers hanging at InsertLotsBS stage — Third-party plugins (Smush Pro, SmartCrawl SEO, WPMU DEV Updates) hook into
wp_insert_post()and make blocking outbound HTTPS calls for every lot processed. With 489+ lots per auction, this caused workers to hang indefinitely on socket reads to WPMU DEV servers (32.193.94.25,32.193.93.106). AddedWP_IMPORTINGconstant at the REST worker entry point and apre_http_requestfilter inCatalogSyncWorkerthat blocks all non-essential external HTTP during the batch post-insertion phase. Loopback (127.0.0.1,localhost) and BidSpirit API calls remain allowed. - Stuck staging rows after force-kill — When workers were force-killed mid-sync, staging rows in
import_historywere left withsyncstart=1and never unblocked. Subsequent sync runs could not see these rows (filtered out byLot::getRawLots()), causing the InsertLotsBS loop to exit immediately with 0 posts processed. Combined with job deduplication (SyncQueue::enqueue()skips if aprocessingjob exists), this created a deadlock where no new sync could proceed.
Files Changed
- Modified:
auctionforge.php,inc/sync/CatalogSyncWorker.php
---
[3.2.2] — 2026-03-17
Full Sync Auction Discovery Fix
Fixes
- Full Sync finds no auctions on fresh sites — The v3
full_syncaction only queried the WordPress database for existing auction terms, but on a freshly deployed site the database has zero auctions. AddedAuctionList::init()discovery step before querying the DB, so Full Sync now fetches all auctions from the BidSpirit API and creates taxonomy terms first, then enqueues catalog sync jobs for each.
Files Changed
- Modified:
auctionforge.php
---
[3.2.0] — 2026-03-14
Webhook Pipeline Fixes, Archive Sync & Admin UI Overhaul
New Features
- Archive Sync — New "Archive Sync" button on Sync Status admin page. Enqueues catalog sync jobs for all ARCHIVED/ENDED auctions. Past auctions now appear in the auction dropdown with an optgroup separator and state label.
- Sync Tasks v3 — Replaced old v2 task cards (importData, importBidSpirit, lotBidSpiritOld) with v3 queue-based tasks. "Sync Active Auctions" and "Sync Archived Auctions" now enqueue jobs via the queue system. Maintenance tasks (Clean Draft/Trash Lots, Clean Orphaned Meta) remain as direct-execution tasks.
- How It Works guide rewritten — Complete rewrite of the admin guide for v3 architecture. Documents webhook-first flow, all 5 job types, queue system mechanics, cron setup (external + WP-Cron), configuration constants, and troubleshooting.
Fixes
- Dual-write removed — Removed legacy handlers from
auctionCatalogUpdated(),auctionDayEnded(), anditemsUpdated()webhook methods. The old handlers were racing with the v3 worker, creating orphaned staging rows inimport_historythat were never processed. All three methods now exclusively use the v3 enqueue → spawn path. - ITEMS_UPDATED webhook — Fixed
itemsUpdated()failing to enqueue jobs. TheITEMS_UPDATEDpayload hasauctionIdnested initemsByLanguage.{lang}[0].item.auctionId, not at the top level. Added extraction logic to resolve it. - ItemUpdateWorker incomplete —
ItemUpdateWorker::process()was only callingLot::bulkSave()(staging table) without runningInsertLotsBSto process staged data into WP posts andbp_meta_data. Added the InsertLotsBS processing step with autocommit restore. Item updates now flow: stage → InsertLotsBS → WP post + meta → cache clear. - Worker spawn reliability — Changed
SyncQueue::spawnWorker()from non-blocking HTTPS to blocking HTTP loopback (http://127.0.0.1with explicitHostheader, 2s timeout). Fixes nginx 403/404 errors when HTTPS loopback hits the default vhost instead of the site's vhost. - API token constant — Plugin expects
AUCTIONFORGE_API_TOKENinwp-config.php(renamed fromUCO_API_TOKENduring the plugin rename). Documented in readme.
Database
- DB version: 22 → 23
Files Changed
- Modified:
inc/controllers/AuctionsAPI.php,inc/sync/ItemUpdateWorker.php,inc/sync/SyncQueue.php,auctionforge.php,admin/view/sync-status.php,readme.txt
---
[3.0.0] — 2025-03-14
New Feature: Webhook-First Sync Architecture (Sync v3)
Overview: Complete redesign of the BidSpirit data synchronisation pipeline. Replaces the old two-phase polling system (importBidSpirit every hour + importData every minute) with a webhook-driven job queue that processes data in near real-time.
Architecture
- 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: webhook → queue → background worker → WordPress posts. - Dual-write mode — During transition, webhooks enqueue jobs AND still run the legacy handlers. Once verified, legacy handlers can be removed cleanly.
- Job deduplication — Prevents duplicate work by checking for existing pending/processing jobs with the same auction_id + job_type.
New Components
- Job Queue System (
inc/sync/SyncQueue.php) — Priority-based FIFO queue with atomic job claiming, status tracking (pending/processing/completed/failed/skipped), worker PID tracking, and automatic stuck job recovery. - Sync Logger (
inc/sync/SyncLogger.php) — Real-time log table for admin console polling with level filtering (info/success/warning/error) and incremental cursor-based retrieval. - Catalog Sync Worker (
inc/sync/CatalogSyncWorker.php) — Processes catalog_sync, full_sync, and day_ended jobs by reusing existingLotList::singleRun()logic. - Item Update Worker (
inc/sync/ItemUpdateWorker.php) — Processes individual item_update jobs with the same logic as the webhookitemsUpdatedhandler. - Background Worker (
crontasks/syncWorker.php) — Async CLI process spawned by webhooks viaexec()or by the safety cron. Claims and processes queued jobs with a configurable timeout (default 240s). - Safety Net (
crontasks/syncSafety.php) — Hourly cron that resets stuck jobs (>10min), spawns workers for pending jobs, runs a 24-hour health check (auto-enqueues full sync if no webhooks received), and purges old data.
Admin UI
- Queue Status Dashboard — New card on Sync Status page showing pending/processing/completed/failed/skipped counts, recent jobs table with real-time refresh, worker status badge, and action buttons:
- Full Sync — Enqueues catalog sync for all active auctions
- Sync Selected — Enqueue a single auction from dropdown
- Spawn Worker — Manually trigger a background worker process
- Live Console — Dark-themed terminal console on the Sync Status page. Polls
af_sync_logevery 1.5s showing timestamped, color-coded log entries from webhooks, workers, queue operations, and the safety cron. Supports pause, clear, and auto-scroll.
Cron Changes
- Removed
importData(ran every minute — ~1,440 PHP executions/day) - Removed
importBidSpirit(ran hourly — ~24 PHP executions/day) - Added
syncSafety(runs hourly at :10 — 24 PHP executions/day) - Net effect: ~62 PHP executions/hour → 1 PHP execution/hour
- WP-Cron safety hook (
auctionforge_sync_safety) — Always-active hourly event, independent of external cron - setup.sh v3 — Updated task definitions, new
migratecommand for interactive v2→v3 transition
Database
- New table:
af_sync_queue— Job queue with status, priority, source, attempts, worker PID, timing columns - New table:
af_sync_log— Real-time log entries with context, level, auction_id, job_id - DB version: 20 → 22
Constants Added
| Constant | Default | Description |
|---|---|---|
|
AUCTIONFORGE_SYNC_WORKER_TIMEOUT| 240 | Worker process timeout in seconds ||
AUCTIONFORGE_SYNC_STALE_JOB| 600 | Seconds before a processing job is considered stuck ||
AUCTIONFORGE_SYNC_HEALTH_CHECK| 86400 | Seconds without webhook before triggering full sync ||
AUCTIONFORGE_SYNC_LOG_RETENTION| 7 | Days to keep log entries ||
AUCTIONFORGE_SYNC_QUEUE_RETENTION| 30 | Days to keep completed queue jobs ||
AUCTIONFORGE_CURL_TIMEOUT| 30 | BidSpirit API cURL timeout in seconds ||
AUCTIONFORGE_PHP_BINARY| /www/server/php/83/bin/php | PHP CLI binary path for spawning workers |AJAX Handlers Added
auctionforge_sync_log_poll— Incremental log polling for live consoleauctionforge_sync_queue_status— Queue counts + recent jobs for dashboardauctionforge_sync_enqueue— Admin-triggered sync actions (full_sync, sync_auction, spawn_worker)
Fixes
- cURL timeout — BidSpiritRequest now enforces a 30-second timeout (was unlimited/0), preventing hung connections from blocking the sync pipeline.
Files Changed
- Modified:
auctionforge.php,inc/coreIncludes.php,inc/controllers/AuctionsAPI.php,inc/BidSpiritRequest.php,admin/view/sync-status.php,crontasks/setup.sh - Created:
inc/sync/SyncQueue.php,inc/sync/SyncLogger.php,inc/sync/CatalogSyncWorker.php,inc/sync/ItemUpdateWorker.php,crontasks/syncWorker.php,crontasks/syncSafety.php
---
[2.7.3.0]
Fixes
- Various stability improvements and bug fixes.
[2.7.1.2]
Fixes
- Added missing
vatAndCommission()function inloadBid()— the sales tax display on single lot pages was never being rendered because the code to callloadTemplateforvat-and-commission-templatewas missing fromapp.js.
[2.7.1.1]
Fixes
- 2 decimal places now only appear in the bid modal (Your max bid, Total Price) via
showDecimalsflag. 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.
[2.7.0.9]
Fixes
- Fixed fatal error during plugin install/upgrade:
class-stats-database.phprequire failure.
[2.7.0.0]
New Features: Advanced Lot Analytics
- Conversion Tracking, Peak Viewing Times, Pre-Sale vs Live Comparison, Category Performance, Share Analytics, Search → View Funnel, Click-Through Tracking, CSV Export, Hot Lot Badge.
- New DB table:
af_lot_shares. New columns onaf_lot_analytics. DB version bumped to 20.
[2.6.0.0]
New Feature: Lot Analytics
- Comprehensive lot view and favorite tracking system with admin dashboard.
[2.5.0.0]
New Features
- Site Statistics System — Full website analytics built into the plugin admin.
- Recently Viewed Items — Profile page tab showing last 20 viewed lots per user.
- Run Identity Check — calls the new wpdeploy
-
v3.7.0.25 Stable May 07, 2026Download v3.7.0.25📦 9.01 MB⚙️ WP 5.2+🔧 PHP 7.2+✓ Tested 6.4
AuctionForge Changelog
All notable changes to the AuctionForge plugin are documented in this file.
---
[3.7.0.21] — 2026-05-05
Added — Connection Diagnostics on the Updates admin page
A new Connection Diagnostics card on Lots → Updates that detects and one-click-heals identity mismatches between this site and the deployment server.
The problem it solves. When a WordPress install is cloned (template → customer site, dev → prod, backup → restore), the cloned wp_options carry the original site's
auctionforge_update_api_keyover to the newhome_url(). The new install then makes API calls to wpdeploy *authenticated as the original site*. wpdeploy looks up by api_key, not by URL, so every/sync-user-tracking,/check-updates,/report-health, and most importantly the Kuma push URL, gets recorded against the WRONGwpdeploy.sitesrow. The cloned site's monitor stays silent; the original's monitor shows traffic that isn't from it.What the diagnostic does:
- Run Identity Check — calls the new wpdeploy
GET /api.php/whoamiendpoint and compares the returnedcaller_site_urlagainsthome_url(). Renders a verdict ("matches" / "MISMATCH") plus the full server-side view (site_id, site_name, last_check, plugin version on file, remote IP). The "Re-register & Reset Kuma" button only appears if there's a mismatch. - Re-register & Reset Kuma — calls
/request-access(which is idempotent onsite_url— wpdeploy returns the canonical api_key for *this*home_url(), regardless of whatever wrong key we were holding), wipesauctionforge_kuma_push_urland any leftover heartbeat cron events, then immediately fires/check-updatesso the api_request interceptor catches the freshly-correct kuma_push_url for *this* site. The keepalive mu-plugin's heartbeat picks it up on the next 60s tick.
Internal
AuctionForge_Auto_Updater::whoami()(new) — thin wrapper overapi_request('whoami', [], 'GET'). Returns the parsed wpdeploy/whoamipayload.AuctionForge_Auto_Updater::reset_connection()(new) — three-step heal: re-register → wipe Kuma cached state → re-fetch via/check-updates. Returns shape suitable forwp_send_json_success.- Two new AJAX actions:
auctionforge_diagnose_connection,auctionforge_fix_connection. Both behindmanage_optionscapability + nonce check. auctionforge_normalize_host()helper for case/scheme/www-tolerant URL comparison.
Server-side companion
Requires the wpdeploy
/api.php/whoamiendpoint added in the same release window. The endpoint is gated behind whatever api_key the caller already presented (a master key returnstype=masterwith no site row; a per-site key returns the site row that key resolves to). Reveals nothing the caller doesn't already implicitly authenticate against.---
[3.7.0.20] — 2026-05-04
Changed
- Kuma heartbeat path is now wpdeploy-independent. The actual heartbeat firing — wp-cron schedule, page-load piggy-back, outbound HTTP — moved out of AF and into the AuctionForge Keepalive mu-plugin (
wp-content/mu-plugins/auctionforge-keepalive.php, bumped to v1.2.1). Once a site has been provisioned once andauctionforge_kuma_push_urlis cached locally, the heartbeat keeps reporting forever even if AF is deactivated, mid-upgrade, deleted from disk, or wpdeploy is offline. The mu-plugin can't be deactivated by WordPress, can't be broken by an AF release, and depends on AF for nothing. - AF only writes the
kuma_push_urloption now. It no longer schedules the cron, no longer fires the heartbeat, and no longer holds any heartbeat-related state. Theapi_request()interceptor still catcheskuma_push_urlfrom/check-updatesand/report-healthresponses and persists it; the mu-plugin reads it from there. - Migration block.
init_hooks()clears any leftoverauctionforge_kuma_heartbeatwp-cron event from AF ≤ 3.7.0.19 on first plugin load after upgrade. The mu-plugin runs the same clear on its ownplugins_loadedhook — belt and braces. The new event the mu-plugin schedules iskuma_heartbeat_tickon a newkuma_60sschedule. AuctionForge_Auto_Updater::kuma_heartbeat()no-opped. Kept as a safety landing pad so any staleauctionforge_kuma_heartbeatwp-cron event that fires one last time before migration kicks in doesn't trip a "no callback registered" warning. Real heartbeat work happens in the mu-plugin.
Added — operator override
AUCTIONFORGE_KUMA_PUSH_URLconstant. Define it inwp-config.phpto point a site directly at Kuma without ever involving wpdeploy:
```php
define('AUCTIONFORGE_KUMA_PUSH_URL', 'https://kuma.example.com/api/push/<token>?status=up&msg=&ping=');
```
The constant takes precedence over the
auctionforge_kuma_push_urloption. With it set, the site can be operated fully outside wpdeploy — useful for one-off installs, customer-managed sites, or disaster-recovery scenarios where wpdeploy is unreachable for an extended period.Internal — Keepalive mu-plugin v1.2.1
The bundled keepalive template at
inc/keepalive/auctionforge-keepalive.template.phpnow also handles Kuma heartbeats. Three layered triggers ensure cadence stays tight regardless of site traffic:1. Dedicated wp-cron event
kuma_heartbeat_tickon a new 60-secondkuma_60sschedule2. Page-load piggy-back on
init: any request older than 50s since the last beat fires another, transient-guarded so concurrent hits coalesce. Free on busy sites; rescues low-traffic sites the moment any visitor arrives.3. Self-heal inside the cron callback: if the event somehow gets cleared, re-arm it before sending the beat.
HTTP is
timeout=2, blocking=false— fire-and-forget, never slows page loads. External IP introspection (ipify → ifconfig.me → icanhazip fallback chain, 24h transient cache) is duplicated in the mu-plugin so it doesn't depend on AF being loaded for the IP lookup.The keepalive installer (
class-keepalive-installer.php) detects theKEEPALIVE_VERSION: 1.2.1header bump and idempotently overwrites every site's mu-plugin on the next AF load. No manual reactivation needed.Failure modes after this release
| State | Heartbeat? |
|---|---|
| AF active and healthy | ✅ via mu-plugin |
| AF deactivated by an operator | ✅ mu-plugin runs anyway |
| AF deleted from disk | ✅ as long as
auctionforge_kuma_push_urloption exists OR constant is set || AF mid-upgrade / partial install | ✅ mu-plugin doesn't depend on AF code paths |
| wpdeploy down (existing site) | ✅ option is cached locally, no wpdeploy round-trip |
| wpdeploy down (brand-new site, never provisioned) | ❌ first-time URL provisioning still needs wpdeploy. One-shot, accepted trade-off. |
| Site has zero traffic AND wp-cron isn't firing | ❌ truly nothing to trigger a beat. Mitigation is OS-level cron / DISABLE_WP_CRON, out of scope here. |
---
[3.7.0.19] — 2026-05-04
Changed
- Reverted Kuma heartbeat cadence: 3 min → 1 min.
auctionforge_kuma_heartbeatis back on thebp_minutelyschedule. With Kuma's 310s silence window, 60s cadence tolerates 4 missed wp-cron ticks before flipping a monitor red — the original "give-it-leeway" semantics. The 3-min cadence introduced in 3.7.0.18 was strictly less chatty but tighter (a single missed tick would trip Kuma), and the trade-off wasn't worth it operationally. - Migration block updated.
init_hooks()now detects any existing event scheduled on a non-bp_minutelycadence (e.g. thebp_3_minutelyset by 3.7.0.18) and re-schedules ontobp_minutely. Sites that took 3.7.0.18 roll back automatically on first plugin load after upgrade. - First-fire jitter narrowed back to 0–60s to match the new cadence.
Notes
- The
bp_3_minutelycron schedule registration inauctionforge.phpis kept (harmless; available for future use). Only the heartbeat scheduling sites have been reverted. - Apparent latency in Kuma flipping a monitor red after a real outage is governed by Kuma's per-monitor
interval(silence-detection window, currently 310s on the wpdeploy/Kuma side), not by this cron's cadence. To detect outages faster, lower the Kumainterval; to add more tolerance to wp-cron drift, raise it.
---
[3.7.0.18] — 2026-05-04
Changed
- Kuma heartbeat cron cadence: 1 min → 3 min.
auctionforge_kuma_heartbeatnow runs on a newbp_3_minutelyschedule (180s) instead ofbp_minutely(60s). This pairs with Kuma's 310s silence-detection window — a single late wp-cron tick (3 min + drift) still lands inside the threshold, but normal traffic to Kuma drops by ~3×. - Random first-fire offset widened from 60s → 180s. With ~50 sites on a single Kuma instance, spreading first-fires across the full 3-min window prevents synchronised bursts every 3 minutes.
- Auto-migration of existing scheduled events. On plugin upgrade
init_hooks()callswp_get_scheduled_event('auctionforge_kuma_heartbeat')and, if the existing event is onbp_minutely, clears it and reschedules ontobp_3_minutely. Idempotent — a no-op once migrated.
Internal
- New cron schedule registered:
bp_3_minutely(BP_MINUTELY * 3= 180s). Defined alongside the existingbp_minutely/bp_ten_minutely/bp_hourly/bp_24_hourlyschedules inauctionforge.php.
---
[3.7.0.17] — 2026-05-04
Fix: "Install Now" always returned
up_to_dateThe
/sync/versionREST endpoint (called by wpdeploy's Install Now button) was always respondingsuccess: false, reason: up_to_dateregardless of the actual installed version, defeating the button's whole purpose.Root cause
rest_force_plugin_update()did:```
delete_site_transient('update_plugins');
$this->check_pending_updates();
$updates = get_site_transient('update_plugins');
```
check_pending_updates()calls the/pending-updatesendpoint on wpdeploy (which returns the deploy queue), but it does not touch the WPupdate_pluginstransient. The transient just got deleted on the line above and never gets re-populated, so theisset($updates->response[…])check always failed → always returnedup_to_date.Fix
- Use
wp_update_plugins()instead — that's what fires thepre_set_site_transient_update_pluginsfilter chain that AF's owncheck_for_updates()callback hooks into to seed the transient. Same pattern is already used correctly ininstall_update()at line 280. - Belt-and-braces: when the request body carries an explicit target
versionand that version is strictly greater than the on-disk plugin version (perversion_compare), bypass the transient check and force the install. This handles edge cases where the transient seeding fails (network blip during the wp-cron cycle, hosting-side cache, etc.) so the explicit Install Now command still does what it says.
---
[3.7.0.16] — 2026-05-04
Server external IP reported to wpdeploy + included in Kuma heartbeats
Each AF install now reports its server's outbound external IP. Two channels:
1. Kuma heartbeat
msg— the per-minute push payload now reads<wp_version>|<plugin_version>|<external_ip>(e.g.6.9.4|3.7.0.16|152.53.187.82) so you can spot at a glance which physical box each site lives on. When a host goes dark, multiple monitors flip red simultaneously with the same IP — instant root-cause hint.2.
/report-healthpayload — a newexternal_ipfield that wpdeploy stores onsites.external_ip. Visible in the Sites admin view as a tappable IP chip; clicking it filters the table to all sites sharing that IP.How the IP is detected
AuctionForge_Auto_Updater::get_external_ip()calls one of three public echo services in turn —api.ipify.org,ifconfig.me/ip,icanhazip.com— with a 4-second timeout each. The first one that returns a valid IP wins. Result is cached in a transient for 24 hours so we don't hit external services on every report cycle.Wpdeploy fallback for older plugins
/report-healthnow also capturesREMOTE_ADDR(orHTTP_CF_CONNECTING_IPwhen behind Cloudflare) when the payload doesn't includeexternal_ip. So sites still on 3.7.0.15 or older start populating their IP today via the same route, no plugin update needed for that data path.---
[3.7.0.15] — 2026-05-04
Kuma monitors land in an "Unallocated" group by default
New AuctionForge installs are auto-enrolled into Kuma under a new top-level group called Unallocated so the operator can review them and drag-drop into the right home (Bidspirit Auction Sites, Stephen's Auctions, Misc Websites, etc.) before classification. Without this every new monitor would appear at the dashboard top level alongside whatever group hierarchy already exists.
What changed (wpdeploy-side, no plugin behaviour change)
KumaProvisionernow ensures an "Unallocated" group exists in Kuma (find-or-create via the same Socket.IOaddpath used for monitors, withtype='group') before provisioning each new push monitor, and passesparent=<group_id>in theaddpayload so the new monitor lands inside it.- The Node helper accepts arbitrary
typeandparentfields on the input payload (previously hardcoded totype='push'). - The group itself gets the same
user_id=1reassignment so it shows up on the human admin's dashboard.
Existing Clumber monitor (id=71) was migrated into the new group as part of this release.
This is a wpdeploy infrastructure change — the AF plugin code is unchanged from 3.7.0.14. Version bumped only to mark a clean snapshot point.
---
[3.7.0.14] — 2026-05-04
Uptime Kuma push heartbeat with automatic enrolment
Each AF install now appears as its own monitor on the central Uptime Kuma at https://kuma.smoothbyteit.dev, beating every minute and flipping red within ~90 seconds when a site goes dark. Auto-enrolled — no manual Kuma UI clicks per site.
How it works
1. First contact: when the plugin calls
/request-accessor/report-health, wpdeploy's newKumaProvisioneropens a Socket.IO connection to Kuma as a dedicatedauctionforge-botuser, calls the officialaddevent, and gets back a fresh push token. The resulting URL is shipped to the plugin in the JSON response askuma_push_url.2. Plugin-side: a generic interceptor on
api_request()persistskuma_push_urlto the optionauctionforge_kuma_push_urlwhenever it appears in any wpdeploy response, and immediately schedules the newauctionforge_kuma_heartbeatcron on the existingbp_minutelyinterval.3. Heartbeat: the cron handler sends a single
wp_remote_getto the push URL each minute withmsg=<wp_version>|<plugin_version>so Kuma's dashboard shows the running stack at a glance. Kuma's silence-detection window is 90s, so a single missed wp-cron tick won't false-DOWN.4. Idempotency: the Kuma monitor's
descriptionfield storeswpdeploy_site_id:<id>. Re-registering the same site short-circuits at the wpdeploy layer (existingkuma_monitor_idonsites), or — if that's missing — Kuma's existing row is reattached via the description anchor. Re-installing the plugin never duplicates monitors.Why Socket.IO and not direct DB insert
Kuma's monitor scheduler does not poll its own DB for new rows —
startMonitors()only loads monitors at boot, and new ones are armed via the authenticated Socket.IOaddevent handler (which callsstartMonitor()and arms the per-monitorsafeBeatsetTimeout). A direct INSERT would create a "phantom" monitor that accepts pushes but never flips DOWN on silence, defeating the whole feature.Notifications + monitor ownership
Provisioner reads existing Kuma notification rows whose channel is Telegram (or marked default-for-new-monitors) and attaches them to every new monitor via the
addevent'snotificationIDList. After the Socket.IOaddsucceeds, the provisioner direct-writesuser_id=1to the new monitor row in Kuma's SQLite — Kuma'saddhandler hardcodesuser_id=socket.userID(the bot at user 2), which causes the frontend's real-time monitor-list updates to skip the admin's session. The follow-up UPDATE stamps ownership to the human admin so monitors render with their full name on the admin dashboard immediately.Failure modes
Every call boundary degrades safely. If Kuma is unreachable when a site registers, registration completes without
kuma_push_url; the next twicedaily/report-healthretries. Heartbeat HTTP failures are silent (which is the desired outcome — Kuma's silence-detection is the signal). Kuma reset / monitor row deleted: provisioner's pre-flight check NULLs the wpdeploy anchors and falls through to fresh provisioning on the next call.Operator setup
Already done: the
auctionforge-botKuma user has been created and credentials populated in wpdeploy'sconfig.php. To rotate or migrate Kuma later, editKUMA_URL/KUMA_BOT_USER/KUMA_BOT_PASSinconfig.php— no plugin redeploy needed.---
[3.7.0.13] — 2026-05-04
Wide shortcode: hide Register button for logged-in users
- When a user is logged in to BidSpirit (
body.bp-login), the Register button is now automatically hidden on wide-format auction cards (bp_upcoming_wideandbp_auction_list layout="wide"). - The View Catalog / Catalog Coming Soon button expands to full width when the Register button is hidden.
- Uses a lightweight
MutationObserverto react to BidSpirit's async session init. - Applied to both
UpcomingAuctionWide.phpandAuctionList.phpshortcode CSS blocks.
---
[3.7.0.12] — 2026-05-03
Stop-word denylist for BidSpirit category-tag concatenations
BidSpirit's
wp_bp_meta_data.tagsfield arrives as PascalCase category names lowercased without separators (uscollectibles,firearmsaccessoriesammunition,usdecorativearts,printsandmultiples). They look like keywords but they're really categories, and on sites where the tags field is populated they completely swamp the top-5 chips for power users (e.g. one buyer's profile was led byuscollectibles 453 viewsdespite that being a label rather than a real interest signal).29 known patterns added to
stop-words.phpso the tokenizer drops them at extraction time. New ones surfacing from sites we haven't seen yet should be added here as they appear; the wpdeploy?tab=keywordscorpus page makes them easy to spot (sort by most users with low lots count and look for non-word concatenations).---
[3.7.0.11] — 2026-05-03
Keyword extractor — capture model years + hyphenated calibers, drop more auction noise
The People view's top-5 keyword chips were filling up with generic descriptors (
household,model,original,assortment) instead of the brand/maker terms (mauser,whitworth,colt) that actually distinguish one buyer from another. Live-data review on the new?tab=keywordsKeyword Corpus page on wpdeploy confirmed the cause: real signal was being lost at the tokenizer stage.Tokenizer changes (
inc/stats/class-keyword-extractor.php)Three pre-passes now run before the standard split-on-non-alpha:
1. Hyphenated / x-separated calibers —
.45-70,.30-06,7.62x54r,8x57. Without this they're split into pure-digit fragments and dropped, losing the actual model identifier.2. Caliber-with-suffix —
9mm,.22lr,.45acp,.380acp. Previously only survived by accident because of the trailing letters; now extracted explicitly.3. 4-digit model years 1700–2099 —
1873,1903,1911,1971. Pure-digit tokens were unconditionally dropped; now retained when year-shaped.Standard pass relaxed to allow 4-digit pure-digit tokens between 1700 and 2099.
Stop-word additions (
inc/stats/stop-words.php)Conservative — only universally empty auction descriptors:
original,marked,accessories,decorative,household,goods,made,condition,assortmentDeliberately NOT added:
antique,vintage,rare,fine— those carry buyer-segmentation signal (antiquarian buyers vs. modern-collectibles buyers). Borderline cases (metal,wooden,american,model) are left to the wpdeploy-side IDF re-rank.Companion change on wpdeploy (no plugin update needed)
refresh_people_rollup.phpnow multiplies each keyword's score by an IDF factor pulled fromkeyword_idf(refreshed hourly byrefresh_lot_keyword_index.php). Generic keywords that appear in many lots get demoted automatically; brand/maker words that only appear on a handful get lifted into the top-5 chips.After deploying this version, reset the
auctionforge_lots_sync_watermarkoption on each site and clear thewp_af_stats_lot_keywordstable to force re-extraction of every lot through the new tokenizer.---
[3.7.0.10] — 2026-05-03
Lots sync — ship resolved CDN image URL, not bare BidSpirit filename
class-lots-sync.phpwas sendingimagesListStr's first comma-token verbatim asimage_url— that's the raw BidSpirit storage value (e.g.001.jpg). Wpdeploy received a bare filename, the browser resolved it against the wpdeploy host, and every lot thumbnail 404'd.The lots-sync now instantiates
LotImageand pulls the resolved CDN URL (LABEL_MEDIUMthumbnail), with fallback toLABEL_ORIGINALand a final defensive check that drops anything that doesn't start withhttp(s)://. Resolution is wrapped in try/catch — a missing class or BidSpirit settings issue leavesimage_urlempty rather than blowing up the sync batch.After deploying this version on a site, reset its
auctionforge_lots_sync_watermarkoption (delete the row) to re-push existing lots through the new resolver. The wpdeploy view skips<img>rendering whenimage_urlisn't a real URL, so dirty rows degrade silently while the watermark catches up.---
[3.7.0.9] — 2026-05-03
Keepalive sweep — auto-clears WP upgrader debris that produces silent "Could not create directory" failures
WordPress 6.x's atomic-rollback flow leaves
wp-content/upgrade-temp-backup/lying around when its post-install cleanup misfires (the user-facing symptom is "Update failed: Could not create directory" after an update that has actually already succeeded). Stalewp-content/upgrade/<plugin>-tmp/and.maintenancelockfiles from crashed upgrades cause the *next* upgrade attempt to fail the same way. None of WP's own scheduled cleanup catches these reliably.The keepalive mu-plugin (
KEEPALIVE_VERSION1.1.0) now sweeps all three classes of debris on every page load, transient-guarded to once per hour. Safety thresholds prevent it touching anything actually in flight:.maintenancefiles less than 5 min old,wp-content/upgrade/*entries less than 60 min old, andupgrade-temp-backup/less than 30 min old are left alone. Wrapped in try/catch with no throws, so the sweep can never block a request.The keepalive installer detects the version bump and rewrites
wp-content/mu-plugins/auctionforge-keepalive.phpautomatically on the next AF load, no manual reactivation needed.---
[3.7.0.8] — 2026-05-03
Shop auction UI refinements & share button settings
Shop (Buy-It-Now) catalog improvements
- Shop sorting dropdown: Added a dedicated sorting dropdown for shop catalogs with options: Recently Added, Price: High, and Price: Low. Sorts by
buyoutPricemetadata. Regular auction catalogs retain the original sorting options. - Removed "Buyout price:" label: On shop lot pages, the redundant "Buyout price:" text before the price is now hidden. Only the price and "Buy Now" button are displayed. Regular auction buyout lots still show the label.
- Removed increments table & terms links: On shop lot pages, the "Increments table" and "Terms and conditions" links are hidden since they don't apply to buy-it-now items. The "Make an inquiry" link remains.
Buyout confirmation modal overhaul
- Sales tax logic: The buyout confirmation modal now follows the same sales tax detection as the regular bid modal. When the auction house has a US state configured, displays "Sales Tax" instead of "VAT", with the correct percentage for same-state buyers and 0% for out-of-state.
- Hide 0% buyer's premium: The Buyer's Premium line is hidden when the commission is 0%.
- Shop-specific text: For shop buyouts, all disclaimer text is replaced with: *"You will receive an email with your invoice, including shipping, and a secure payment link."*
- Shop-specific buttons: "I don't Agree" → "Cancel", "I Agree" → "Buy". The "Terms of sale" button is removed for shop buyouts. Non-shop buyouts retain the original layout.
Purchase confirmed screen
- Title changed from "Confirm purchase:" to "Purchase Confirmed".
- Thank you message updated to: *"Thank you for your order. We will confirm your order within 1-2 business days and email you an invoice, including shipping, and a secure payment link."*
Share button settings (Appearance tab)
- Added a Share Buttons section to the BidSpirit Appearance settings tab with individual checkboxes for each sharing platform: Copy Link, WhatsApp, Facebook, Telegram, X (Twitter), VK, Pinterest, and Email.
- All platforms default to enabled (shown). Unchecking a platform hides that share button on all lot pages (both shop and regular auctions).
---
[3.7.0.7] — 2026-05-02
Identity stitch on bidder login — keyword interest tallying now actually fires
Why
The keyword extractor was filling
wp_af_stats_lot_keywordscorrectly (197 lots, 734 distinct keywords on Clumber), butwp_af_user_interestsandwp_af_user_recent_activitywere both empty — zero rows of any dimension. Same on every site running the new sync streams.Root cause: identity stitching (visitor_hash → email) only fired in the tracker AJAX when
is_user_logged_in()returned true. On these auction sites the actual bidders authenticate via BidSpirit, never aswp_users— so the WP login check was always false, the stitch table stayed empty, andmaybe_record_lot_view($url, $email, …)got called with an empty email and bailed out before tallying. Lot views by real bidders never landed in the user-side interest profile.What changed (no auth-path intervention)
The fix piggybacks on the *existing* fire-and-forget tracking AJAX that already runs after a successful BidSpirit login (
afLogIP("login", bidspiritUser)). It does not touch the BidSpirit auth path itself.inc/ip-logger.phpauctionforge_ajax_log_ip()— after the existingauctionforge_user_trackinginsert, if the request carries avisitor_hashand the email is valid, callsAF_Stats_Visitor_Email_Map::record($vh, $email, $ip). Wrapped in try/catch so any failure here can never break the existing tracking response.assets/js/app.js+src/js/app.jsafLogIP()— readslocalStorage['af_vid'](defensively, ITP/private-mode safe) and includes it asvisitor_hashin the POST body.inc/stats/class-stats-init.phpmaybe_record_lot_view()— when$emailis empty (the common case for BidSpirit-only bidders) but avisitor_hashis present, falls back toAF_Stats_Visitor_Email_Map::lookup($visitor_hash). If a stitch exists, the view tallies; if not, it stays anonymous.
Net effect: a bidder logs in (BidSpirit), the post-login tracker AJAX fires as it always has, and now also writes one extra row into
af_stats_visitor_emails. From that point onward, every page they view on the same browser/device tallies intoaf_user_interestskeyed on their email. The BidSpirit transaction itself is untouched.---
[3.7.0.6] — 2026-05-02
Critical fix —
X-API-Keyheader collision with sibling SmoothByte pluginsWhat was wrong
On any site running both AuctionForge and another SmoothByte-stack plugin that also points its updater at
wpdeploy.smoothbyteit.dev(e.g.seo-aeo-optimizer), the second plugin'shttp_request_argsfilter overwrote AuctionForge'sX-API-Keyheader on every outbound API call. Wpdeploy then 401'd because the key it received belonged to a different plugin instance — usually aseo_aeo_update_api_keythat wpdeploy had no record of.The symptom was a quiet, total auth failure:
report-health,check-updates, everysync-*route, all 401. The watchdog flagged streams as "gone" and updates stopped flowing. Affected sites: any install where the AuctionForge key and the sibling plugin's key happen to differ. Sites where both plugins shared a key were silently safe (the overwrite was a no-op).Fix
AuctionForge_Auto_Updater::add_download_auth()now refuses to clobber an existingX-API-Keyand, for download URLs, only stamps when the URL slug matches our own. That keeps targeted calls fromapi_request()intact regardless of filter ordering, and prevents either plugin from writing its key onto the other's download URL.The same fix has been applied to
seo-aeo-optimizerso both ends of the collision are defensive.---
[3.7.0.5] — 2026-05-02
Sync Status admin panel — diagnostic + manual triggers in wp-admin
Why
Diagnosing sync issues used to require shell access on the site or piecing together state from wpdeploy's app.log. This release surfaces the same diagnostics inside wp-admin so a site admin (or anyone with
manage_options) can see exactly what's happening and trigger fixes in one click.Lives inside the existing Sync Status menu (
Lots → Sync Status) — appended below the existing content as a "Sync Diagnostics & Manual Controls" section, no duplicate menu entry.What's on the panel
Connection summary — plugin version,
af_stats_db_version, wpdeploy server URL, last 8 chars of API key, keepalive install state + auto-reactivation count.Sync streams table — for each of the 10 cron hooks (user-tracking, user-profile, user-interests, user-activity, lots, bids+wins, vulnerabilities, report-health, check-updates, fraud-enforcement):
- Configured schedule
- Last fired timestamp + status colour-coded (green=success, blue=idle/empty, red=error)
- Record count from last run
- Next scheduled run
- Current watermark (where applicable)
- "Fire now" button — clears doing_cron, calls
do_action($hook)synchronously, shows the result
One-shot utilities
Test wpdeploy connection— calls/api.php/infowith the site's API keyClear stuck cron lock— deletes thedoing_crontransient (the classic fix when scheduled events stop firing)Reinstall keepalive— overwritesmu-plugins/auctionforge-keepalive.phpfrom the bundled templateBackfill bids from legacy tracking— replayslast_event_type='bid'rows fromwp_auctionforge_user_trackingintowp_af_bid_eventsso the bids-wins stream picks them up. Useful for sites that have years of bid history in the legacy table but nothing in the new queueRun all due events now— clears doing_cron and fires everyauctionforge_*cron event whose timestamp is past due, in one go
Live response output panel shows the JSON returned from each action so you can see what just happened without leaving the page.
Files Changed
- Created:
inc/admin/class-sync-status-page.php - Modified:
inc/stats/class-stats-init.php(load + init the panel) - Modified:
admin/view/sync-status.php(appendAF_Sync_Status_Page::render_panel()call at the bottom) - Modified:
auctionforge.php(Version 3.7.0.4 → 3.7.0.5)
Verification
Navigate to Lots → Sync Status in wp-admin on any 3.7.0.5 site. Scroll past the existing content to the new "Sync Diagnostics & Manual Controls" section. Click "Test wpdeploy connection" — you should see
{"success": true, "auth_type": "site"}. Click "Fire now" on any stream — the row's last-fired timestamp should refresh after 1–2 seconds.---
[3.7.0.4] — 2026-05-02
Self-healing: failed plugin updates can no longer take a site offline
Why
WordPress's plugin updater isn't transactional — when an update fails partway (corrupt unzip, fatal during the new version's
plugins_loaded, disk pressure, theme conflict, etc.) WP often deactivates the plugin and leaves the site without it. Once AuctionForge is dropped fromactive_plugins, no AF code runs again — including its sync handlers — until someone notices and reactivates manually. On the AuctionForge site fleet, this had quietly happened to ~5 sites we found; almost certainly more on production sites we don't have filesystem access to.This release ships an autonomous watchdog that lives outside the AuctionForge plugin entirely so it survives even when AF gets knocked out.
What changed
1. Self-installing keepalive (mu-plugin)
inc/keepalive/auctionforge-keepalive.template.php— a 50-line WordPress must-use plugin. Lives inwp-content/mu-plugins/, which WordPress can't deactivate. On everyplugins_loaded(priority 1, before any regular plugin), it checks: isauctionforge/auctionforge.phpon disk but missing fromactive_plugins? If yes AND the file has a validPlugin Name:header (smoke check — don't reactivate a corrupt zip), it re-adds AF andincludes the file in the same request.inc/keepalive/class-keepalive-installer.php— runs on every successful AF load. Copies the template intowp-content/mu-plugins/auctionforge-keepalive.phpif missing or version-bumped. Idempotent: comparesKEEPALIVE_VERSIONheaders, only writes on change. Refuses to overwrite a foreign mu-plugin (defensive against name collisions). Failure is non-fatal — install errors are recorded inwp_optionsfor wpdeploy visibility but never throw.
Net effect. Any site that successfully loads AF 3.7.0.4 or later will have the keepalive permanently installed in mu-plugins. From that point forward, even if a future update hard-fails, the keepalive recovers AF on the next pageview without any manual intervention or filesystem access. Crucially: this works on sites we don't own — the keepalive ships inside the AF zip, gets installed during the first successful update, and lives in mu-plugins thereafter.
2. Forensic markers
The keepalive writes three options on each recovery:
auctionforge_auto_reactivated_at— most recent recovery timestampauctionforge_auto_reactivated_count— total recoveriesauctionforge_auto_reactivated_failed_at— set when the keepalive saw AF on disk but with no Plugin Name header (genuinely corrupt — needs operator attention)
These get picked up by the AF sync streams and surfaced on the wpdeploy dashboard so you can see which sites have been quietly recovering themselves and whether a particular release is failing more than it should.
3. Companion: post-update-silence alerts on wpdeploy (server side)
Wpdeploy's
report-healthroute now compares incomingplugin_versionagainst the row and writeslast_version_changed_at+previous_plugin_versionon change. TheSyncWatchdogcron then alerts if a site has reported a version change but not sent any heartbeat for 2+ hours since — likely a failed install. Emitssync_incidentsrows withkind=post_update_failureso the existing Telegram fan-out picks them up. Each version-change event alerts at most once.Files Changed
- Created:
inc/keepalive/auctionforge-keepalive.template.php,inc/keepalive/class-keepalive-installer.php - Modified:
inc/stats/class-stats-init.php(callAF_Keepalive_Installer::maybe_install()on every plugin load) - Modified:
auctionforge.php(Version 3.7.0.3 → 3.7.0.4)
Companion server-side changes (already deployed on wpdeploy.smoothbyteit.dev — not in this zip):
sitestable:last_version_changed_at TIMESTAMP NULL,previous_plugin_version VARCHAR(20) NULLapi.php/report-health route detects version changesSyncWatchdog::maybe_alert_post_update_failure()emits the new alert kind
Verification
1. Drop a 3.7.0.4 install on any site. Confirm
wp-content/mu-plugins/auctionforge-keepalive.phpexists post-load.2. Manually deactivate AF from the database (
DELETE FROM wp_options ...active_plugins...). Hit the homepage. AF reappears inactive_plugins;auctionforge_auto_reactivated_countincrements.3. Delete
mu-plugins/auctionforge-keepalive.php. Trigger AF load (any pageview). The file reappears.4. Bump KEEPALIVE_VERSION in the source template, ship a new release, observe the installed mu-plugin update on next AF load.
Operator notes
- Sites currently in the broken state (AF deactivated, no keepalive yet) are NOT auto-rescued by this release — they need a one-time manual reactivation in wp-admin OR a fresh AF install via wp-admin's Upload Plugin. After that, the keepalive is in place and future failures self-heal.
- The post-update-failure alert won't fire for upgrades that happened before this release (no
last_version_changed_atwas recorded). It activates from the first version change wpdeploy sees from each site after this update lands.
---
[3.7.0.3] — 2026-05-02
Fix: profile re-sync on login / profile-edit / register (no more empty names)
Why
The hourly profile sync uses a
user_registeredwatermark — once a user has been pushed once, the watermark advances past them and they're never re-pulled. That meant:1. Existing users whose first_name/last_name became populated AFTER their first sync stayed empty on wpdeploy forever.
2. BidSpirit-driven sites that don't write WP's standard
first_name/last_namefields shipped empty rows even though the canonical name was visible indisplay_name.The People view was showing
—for the name on rows that absolutely had a name available — just not where the sync handler was looking.Fixes (
inc/sync/class-profile-sync.php+inc/stats/class-stats-init.php)AF_Profile_Sync::push_for_user_id($user_id, $blocking=false)— new public method that builds a single user's profile row, normalises it, and POSTs to wpdeploy bypassing the watermark. Non-blocking by default (wp_remote_postwithblocking=false, timeout=2s) so login latency is unaffected.build_user_row($user_id)extracted as a reusable helper. Both the hourly batch and the on-demand push call it. Centralises role-filtering + display_name fallback + usermeta probing.display_namefallback. Whenwp_usermeta.first_name/last_nameare both empty (typical on BidSpirit-only sites),build_user_row()parsesdisplay_name("John Smith" → first=John, last=Smith) so we don't ship a row with a blank name when the data is sitting on the user record itself.- Three new action hooks registered in
class-stats-init.php::init(): wp_login→push_for_user_id($user->ID)— every login refreshes the rowprofile_update→ same — profile edits in wp-admin refreshuser_register→ same — new registrations get pushed instantly (instead of waiting up to 60 min for the next cron tick)
Files Changed
- Modified:
inc/sync/class-profile-sync.php(refactor + new method + display_name fallback) - Modified:
inc/stats/class-stats-init.php(three new action hooks) - Modified:
auctionforge.php(Version 3.7.0.2 → 3.7.0.3)
Verification
1. On a 3.7.0.3 site, find a user whose
wpdeploy.user_profiles.first_nameis empty:SELECT site_id, email, first_name FROM user_profiles WHERE email='something@example.com'2. Log in as that user (or have them log in).
3. Within ~2 seconds, re-query —
first_nameshould now be populated, either from the standard meta key OR parsed fromdisplay_name.4. The non-blocking POST means the user's login experience is unchanged — no spinner, no extra latency.
Operator note
Existing wpdeploy rows with empty
first_name/last_namewill refresh automatically as users log in or edit their profile. To force a one-shot re-walk of every user on a site (regardless of watermark), reset the watermark there:DELETE FROM wp_options WHERE option_name='auctionforge_profile_sync_watermark';Next hourly cron will re-pull every non-admin user with the new fallback applied.
---
[3.7.0.2] — 2026-05-02
Fix: sync-lots datetime mismatch + idle syncs now heartbeat
Why
Two issues surfaced in the wpdeploy Sync Health dashboard:
1. Every site's
sync-lotswas stuck onapi_error. The plugin sendslast_modifiedstraight fromwp_bp_meta_data.lastUpdate, which is a Unix epoch string ("1756919754"). wpdeploy'slots.last_modifiedcolumn is aDATETIME, so MariaDB rejects the insert withSQLSTATE[22007]: Incorrect datetime value. The handler recordsapi_errorand the watermark never advances, so every cron tick re-fails on the same batch.2. Sites with nothing to sync looked dead. When a sync handler had an empty batch (e.g. no non-admin users yet) it was returning early without POSTing anything. wpdeploy's
update_sync_health()only fires on a successful POST, sosites.sync_health_jsonstayed NULL and the dashboard showed grey dots — indistinguishable from a broken cron. WP-Cron was actually firing fine; the watchdog just couldn't tell.Fixes
inc/sync/class-lots-sync.php— newepoch_to_datetime()helper converts the BidSpirit epoch field to UTCY-m-d H:i:sbefore shipping. Idempotent: already-formatted datetimes pass through untouched, invalid values becomeNULL.inc/sync/class-sync-base.php::run()— always POST, even when the batch is empty. Empty payload is{records: []}and wpdeploy's existing handlers handle it gracefully (loop is skipped,update_sync_health()still fires withsynced=0). This makes the dashboard reflect cron liveness, not just data flow.
Files Changed
- Modified:
inc/sync/class-lots-sync.php - Modified:
inc/sync/class-sync-base.php - Modified:
auctionforge.php(Version 3.7.0.1 → 3.7.0.2)
Verification
1. On Clumber:
do_action('auctionforge_sync_lots')— confirm the previousauctionforge_last_sync-lots_status = api_errorflips tosuccess(N)and thatwpdeploy.lotsnow contains rows.2. On a site with no non-admin users:
do_action('auctionforge_sync_user_profile')— confirmauctionforge_last_sync-user-profile_status = idle(0)AND that wpdeploy's Sync Health page now shows a green dot for that cell.---
[3.7.0.1] — 2026-05-02
Fix: marketing data leaks WordPress admins into the people list
Why
After the 3.7.0.0 rollout the central
peopleview on wpdeploy was showing site administrators alongside real auction-house users — thesync-user-profilehandler read straight fromwp_userswith no role filter, so any account with administrator/editor/author/contributor/shop_manager capabilities was getting shipped as if it were a buyer. Marketing audiences must contain buyers, not staff.Fixes (
inc/sync/class-profile-sync.php)- The
read_batch()SQL now LEFT JOINs{$wpdb->usermeta}on the prefix-aware capabilities key ({$wpdb->prefix}capabilities) and filters out any user whose serialized capabilities meta_value containsadministrator,editor,author,contributor,shop_manager, orsuper_admin. Users withIS NULL(no roles registered) are still allowed through — those are typically subscribers/buyers on this fleet. - Watermark on
auctionforge_profile_sync_watermarkis unchanged; the next run after upgrade picks up the same batch with the new filter applied. Operationally the wpdeploy team also wiped the existing admin rows fromuser_profiles,user_interests,user_recent_activity,bids_wins, andpeopleto clear the leak server-side — total of 35 rows scrubbed.
Files Changed
- Modified:
inc/sync/class-profile-sync.php - Modified:
auctionforge.php(Version 3.7.0.0 → 3.7.0.1)
Verification on Clumber dev
1. Find a logged-in admin:
SELECT u.user_email FROM wp_users u JOIN wp_usermeta um ON um.user_id=u.ID AND um.meta_key='wp_capabilities' WHERE um.meta_value LIKE '%administrator%';2. Reset the watermark:
DELETE FROM wp_options WHERE option_name='auctionforge_profile_sync_watermark';3. Trigger sync:
do_action('auctionforge_sync_user_profile');4. On wpdeploy: confirm those admin emails do NOT appear in
user_profiles(SELECT * FROM user_profiles WHERE email='admin@…';returns zero rows).Privacy / scope
- No API contract changes. The wpdeploy
/api.php/sync-user-profileroute accepts the same payload shape; this is purely a source-side filter narrowing what gets sent.
---
[3.7.0.0] — 2026-05-02
Cross-site user data lake — full Phase 2 + Phase 3 build
Why
AuctionForge sites were exposing per-lot engagement (views, favourites, bids, wins) keyed only on the anonymous
af_vidlocalStorage hash, with no central aggregation. Marketing — even the "collect data now, send later" phase — needs a per-person view across the whole AF network: name + phone + postcode + country + IP + device fingerprint + the keywords they engage with + the bids they place + the lots they win, all rolled up across every site they've used. This release wires every piece needed for that, and keeps it sustainable: per-site aggregates rather than raw event firehose, watermarked syncs with retry, 14/30-day site-side retention, watchdog + Telegram alerts for dead streams.See
/root/.claude/plans/i-want-to-add-synthetic-goose.mdfor the full architecture.New tables (idempotent dbDelta on the existing
plugins_loadedmigration path)wp_af_stats_lot_keywords— per-lot keyword cache. Title + tags + author tokenized (lowercase → drop stop-words → drop ≤2-char → drop pure-digit), one row per (post_id, keyword). Populated onsave_post_lot.wp_af_user_interests— running tally per(user_email, dimension, dimension_value)where dimension ∈keyword | category | author | price_band. UPSERT-keyed so increments are atomic. Bounded by users × distinct interests (typically a few dozen rows per user).wp_af_user_recent_activity— capped per-user activity log (last 50 events per email). Seeds the drill-down timeline on the wpdeploy person view.wp_af_bid_events— bid + win events (auto-created by the bids sync handler). Drained and shipped to wpdeploy hourly.synced_atcolumns added towp_af_stats_pageviews,wp_af_stats_sessions,wp_af_stats_searches,wp_af_stats_outbound. Powers the durable sync-and-purge lifecycle.af_stats_db_versionbumped 2 → 3. The existingAF_Stats_Init::maybe_create_tables()picks up the new tables on the next admin page load after auto-update.
New helper classes
AF_Keyword_Extractor(inc/stats/class-keyword-extractor.php) — pure tokenizer + cache writer + read-through helper. Hookssave_post_lotto refresh on lot changes. Stop-words tunable viaapply_filters('af_keyword_stop_words', ...).AF_User_Interests(inc/stats/class-user-interests.php) —record_view / record_favorite / record_bid / record_win. All idempotent UPSERTs. CallsAF_Stats_Tracker::should_skip()first so admins/bots never pollute interest profiles.AF_Sync_Base(inc/sync/class-sync-base.php) — abstract durability backbone. Readssynced_at IS NULLbatches, POSTs, marks rows synced only on a confirmed 200, retries on next cron run if the POST fails. Idempotent UNIQUE keys on the wpdeploy side mean retries never duplicate.AF_Profile_Sync/AF_Interests_Sync/AF_Activity_Sync/AF_Lots_Sync/AF_Bids_Sync— five concrete sync streams.AF_Data_Purge(inc/maintenance/class-data-purge.php) — daily cron: 14-day floor on synced rows, 30-day hard cap with CRITICAL alert if any unsynced row hits the cap (which would mean wpdeploy has been unreachable for a month).
New cron schedules (auto-registered on plugins_loaded if
auctionforge_update_server_url+_api_keyare configured)| Hook | Schedule | Endpoint |
|---|---|---|
|
auctionforge_sync_user_profile| hourly |POST /api.php/sync-user-profile||
auctionforge_sync_user_interests| hourly |POST /api.php/sync-user-interests||
auctionforge_sync_user_activity| hourly |POST /api.php/sync-user-activity||
auctionforge_sync_lots| every 10 min |POST /api.php/sync-lots||
auctionforge_sync_bids_wins| hourly |POST /api.php/sync-bids-wins||
auctionforge_purge_synced_data| daily | (purge cron — local) |All sync handlers are watermarked or
synced_at-gated; cron mid-run failure is harmless because the next run picks up the same rows.Hooks fired
af_stats_pageview_recorded($url, $email, $visitor_hash)— fires insideAF_Stats_Ajax::handle_track()after a logged-in pageview is recorded. Default listener resolves URL → lot post →AF_User_Interests::record_view().af_stats_lot_favorited($email, $post_id)— fires from the existinglot_analytics_record_favoriteAJAX handler when a watchlist add happens. Default listener callsrecord_favorite().
Server-side companion (wpdeploy)
This release is paired with wpdeploy changes (handled out-of-band; not in the plugin zip):
- 5 new API routes matching the sync streams above. All return
synced+ watermark metadata so the plugin can advance / mark rows synced. update_sync_health()helper in wpdeploy — every successful sync POST writes(stream, last_seen_at, last_synced_count, state)intosites.sync_health_json.SyncWatchdog— 5-minute cron on wpdeploy that scans every (site × stream) cell and runs anok → overdue → gone → recovering → okstate machine. Emits alerts via the existingsync_incidentsTelegram fan-out.- People section in the wpdeploy admin —
?tab=people(cross-site rollup with top keywords / lifetime spend),?tab=person&email=...(drill-down with timeline + bids),?tab=people-export(Google Customer Match + Meta Custom Audience CSV with sha256 hashing per spec). ?tab=sync-health— site × stream traffic-light grid showing every sync's state.
Files Changed
- Created:
inc/stats/class-keyword-extractor.php,inc/stats/class-user-interests.php,inc/stats/stop-words.php - Created:
inc/sync/class-sync-base.php,inc/sync/class-profile-sync.php,inc/sync/class-interests-sync.php,inc/sync/class-activity-sync.php,inc/sync/class-lots-sync.php,inc/sync/class-bids-sync.php - Created:
inc/maintenance/class-data-purge.php - Modified:
inc/stats/class-stats-database.php(DB_VERSION = 3, new dbDelta calls, synced_at column adds) - Modified:
inc/stats/class-stats-init.php(require new classes, register sync crons, wireaf_stats_pageview_recordedandaf_stats_lot_favoritedlisteners) - Modified:
inc/stats/class-stats-ajax.php(fireaf_stats_pageview_recordedafter pageview record; fireaf_stats_lot_favoritedon watchlist add) - Modified:
auctionforge.php(Version: 3.6.4.0 → 3.7.0.0)
Verification on Clumber dev
1. After auto-update + first wp-admin page load:
wp_af_stats_lot_keywords,wp_af_user_interests,wp_af_user_recent_activityall exist;af_stats_db_version = 3.2. Save a test lot titled
"Pair of Victorian silver candlesticks by Mappin & Webb"→wp_af_stats_lot_keywordshas rows forvictorian, silver, candlesticks, mappin, webb(and notpair, of, by).3. Log in as throwaway test user, view 3 of those lots →
wp_af_user_interestsshows(test@…, keyword, 'victorian', view_count=3).4. Wait one hourly cron, confirm
wpdeploy.user_interestsmirror via the wpdeploy admin →?tab=people→ search for the test email.5. Confirm
wpdeploy.sites.sync_health_jsonhasuser-interests.state = 'ok'for the Clumber site.6. Pause the cron, wait 2h, watch the watchdog flip the cell to
overdueand emit a Telegram alert.Privacy / scope
- Admins and bots are filtered out at write time via
AF_Stats_Tracker::should_skip(). - Email is normalized lowercase + trim before storage; phone normalized to E.164 (UK-aware) on the sync side.
- No outbound activation yet — wpdeploy stores everything but doesn't send anything to anyone. Marketing send mechanics (consent flag, suppression list, sender) explicitly deferred.
---
[3.6.4.0] — 2026-05-02
Identity stitching: visitor_hash → user_email
Why
The
af_stats_*tables (pageviews,sessions,searches,outbound) and the lot-engagement tables (af_lot_analytics,af_lot_shares) currently store activity keyed only on the anonymousaf_vidlocalStorage hash — there is no link from any browsing event to the user's email even when they're logged in. Without that link, the central wpdeploy server can never aggregate behavioural data on a per-person basis, which is the prerequisite for the cross-site user-data lake being built on wpdeploy (see/root/.claude/plans/i-want-to-add-synthetic-goose.mdPhase 1).This release adds the bridge: every authenticated tracker hit records a
(visitor_hash, user_email)pair into a new table. From here on, anonymous browsing can be resolved to an email via JOIN for any session the user was logged in.Changes
- New table
wp_af_stats_visitor_emails—(visitor_hash, user_email, ip_address, first_seen, last_seen)withUNIQUE(visitor_hash, user_email)+ index onuser_email. Created viadbDeltainside the existingAF_Stats_Database::create_tables()so it ships through the standardplugins_loadedmigration path — no manual reactivation needed after auto-update. af_stats_db_versionbumped 1 → 2.AF_Stats_Init::maybe_create_tables()now compares against the newAF_Stats_Database::DB_VERSIONconstant rather than a hard-coded< 1, so future schema bumps (Phase 2 onwards) just require constant edits + new dbDelta calls.- Identity record on every authenticated tracker hit.
AF_Stats_Ajax::handle_track()now callsAF_Stats_Visitor_Email_Map::record($visitor_hash, $email, $ip)wheneveris_user_logged_in()is true. Trust boundary: the email is read server-side fromwp_get_current_user()— clients cannot assert who they are. - Defensive table-exists guard. The new helper short-circuits silently if the migration hasn't run yet on a given site (race window on the very first request after auto-update); the next request finds the table and proceeds. No fatals, no missing rows.
- Email normalised at write time — lowercase + trim +
is_email()validation before storage. Marketing audience match-rates downstream depend on consistent casing.
Files Changed
- Created:
inc/stats/class-visitor-email-map.php - Modified:
inc/stats/class-stats-database.php(DB_VERSION constant; new table; drop_tables list) - Modified:
inc/stats/class-stats-init.php(require new helper; migration check uses constant) - Modified:
inc/stats/class-stats-ajax.php(record pair inhandle_track) - Modified:
auctionforge.php(Version header bump)
Verification on Clumber dev
1. After auto-update, load any
wp-admin/*page once →wp_af_stats_visitor_emailsexists,af_stats_db_version = 2.2. Log in as a test user, browse 5 lots → exactly one row in
wp_af_stats_visitor_emailsfor that(visitor_hash, email)pair, withlast_seenupdating on each hit.3.
SELECT email FROM wp_af_stats_visitor_emails WHERE visitor_hash IN (SELECT visitor_hash FROM wp_af_stats_pageviews WHERE created_at > NOW() - INTERVAL 1 HOUR)returns the test email — proving the JOIN works.Privacy / scope
- This change writes a
(visitor_hash, email)pair to a single new table on the AF site. Nothing is sent to wpdeploy yet — the sync stream lands in Phase 2. - Anonymous (logged-out) browsing is unaffected: no row is created until the user authenticates.
- Bots are still skipped via
AF_Stats_Tracker::is_bot()before any tracking writes.
---
[3.6.3.1] — 2026-05-01
Fix: New lots never processed + Live console improvements
Why
When BidSpirit adds new lots to an auction (e.g. items 683-692), the sync pipeline correctly staged all 709 lots into
import_historybut the InsertLotsBS processing loop exited after the first batch of 500 unchanged lots, never reaching the genuinely new lots at the tail of the queue. This caused new lots to remain permanently stuck in staging — synced but never created as WordPress posts.Separately, the admin Live Console was replaying the entire log history from the beginning on every page load, and showed long silent gaps during API calls with no indication of what the worker was doing.
Fixes
- InsertLotsBS loop break condition — The stage 5 insert loop in
CatalogSyncWorker::process()andprocessDayEnded()previously broke whenupdated lots === 0, even if the batch had cleared hundreds of unchanged ("unupdated") lots from the queue. New lots with higher IDs were never reached. Now breaks only when bothupdated lotsandunupdated lotsare 0, meaning the staging queue is truly empty. - Live Console starts from current position —
consoleSinceIdwas hardcoded to0, causing the console to page through the entireaf_sync_logtable (50 rows at a time) before reaching real-time entries. Now initializes toSyncLogger::getLatestId()so only entries created after page load appear. queueIsActivedeclaration order — Variable was declared after functions that referenced it, causing the console to always start at the slow 3s polling rate even when a worker was active. Moved declaration before first use.- Progress logging during API calls —
LotList::auctionProcessing()made 2-3 BidSpirit API calls with zeroSyncLoggerentries, creating long silent gaps in the console. Added log entries for API fetch start, response received (with duration), data staged, and API errors. - Per-auction progress in bulk runs —
LotList::run()now logsProcessing auction X/Y: {id}for each auction in the bulk loop, and logs skipped auctions. processDayEndedinsert loop logging — Added batch progress logging and timeout guard matching theprocess()method pattern. Previously this loop was completely silent.
Files Changed
- Modified:
inc/sync/CatalogSyncWorker.php,inc/import/LotList.php,admin/view/sync-status.php
---
[3.6.3.0] — 2026-05-01
Public Auctions API — Token Authentication
Why
The
/wp-json/auctionforge/v1/public/auctionsendpoint added in v3.6.2.9 was publicly accessible. Since auction data should only be served to authorized aggregator sites, the endpoint now requires a valid auth token.Changes
- Token verification — The
PublicAuctionsREST endpoint now validates anX-AF-Tokenheader (or?token=query parameter) against the site's existing Webhook auth token from AuctionForge settings. - Returns
401 Unauthorizedfor missing/invalid tokens and403 Forbiddenif no auth token is configured on the site. - Uses
hash_equals()for timing-safe comparison.
Files Changed
- Modified:
auctionforge.php,inc/api/PublicAuctions.php
---
[3.6.2.9] — 2026-05-01
Public Auctions REST API Endpoint
Features
- New REST endpoint
GET /wp-json/auctionforge/v1/public/auctions— Exposes auction list data (title, date, image, state, catalog link) for consumption by the AuctionForge Hub plugin on parent/main sites. - Parameters:
type(upcoming or past, default: upcoming),limit(max results, default: 50). - Handles multi-day auctions with correct part numbers and catalog links.
- Returns auction metadata including
auction_id,source_site, andday_indexfor deduplication.
Files Changed
- Modified:
auctionforge.php,inc/coreIncludes.php - Created:
inc/api/PublicAuctions.php
---
[3.6.2.8] — 2026-04-30
Suppress alerts for transient retry conditions
Why
The "BidSpirit API returned 0 lots — catalog may not be ready yet" message is logged when the BidSpirit webhook fires before the auction catalog is fully published. The safety cron retries the job automatically and it usually succeeds on the next attempt — there's no operator action required, so a Telegram alert is just noise.
Fix
- New private helper
SyncLogger::isSuppressedFromAlerts($message, $context)matches the message against a substring allowlist of known-transient errors. When matched, the row is still inserted intoaf_sync_log(so the in-app sync console still shows the retry chain) but theauctionforge_sync_error_loggedfan-out action does NOT fire — wpdeploy and Telegram stay quiet. - Default suppression substrings:
"BidSpirit API returned 0 lots","catalog may not be ready yet". - Extendable via the new
auctionforge_sync_alert_suppress_patternsfilter — themes/MU plugins can add their own substrings.
Files Changed
- Modified:
auctionforge.php,inc/sync/SyncLogger.php
---
[3.6.2.7] — 2026-04-30
Typo fix
- Settings → Connections tab: the placeholder/help text under the Server field showed
https://my-accaunt.bidspirit.com/(extra "a"). Now readshttps://my-account.bidspirit.com/.
Files Changed
- Modified:
auctionforge.php,inc/controllers/Settings.php
---
[3.6.2.6] — 2026-04-30
Fix stale
plugin_versionin reportsWhy
Sites were reporting their old version to wpdeploy long after they'd been upgraded — e.g. Lonsdale Auctioneers ran v3.6.1.1 but kept telling wpdeploy it was on v2.9.6. Root cause: the constant
AUCTIONFORGE_VERSIONis read from the plugin file'sVersion:header *once at plugin load*, then frozen into$this->current_versionon the auto-updater instance. After a plugin upgrade replaces the file on disk, existing PHP-FPM workers keep using the cached constant value until they're recycled, so every report from those workers carries the old version.Fix
- New helper
AuctionForge_Auto_Updater::get_live_version()reads the version directly from the plugin file's header on each call (viaget_file_data()— uncached). report_health,push_sync_error_immediate, andretry_sync_errorsnow sendget_live_version()instead of the cached constant.- The pre-existing iteration through active plugins inside
report_healthalready usedget_plugin_data()per plugin, so secondary plugin entries were already accurate; only the top-levelplugin_versionfield was stale.
Files Changed
- Modified:
auctionforge.php,inc/class-auto-updater.php
---
[3.6.2.5] — 2026-04-30
Real diagnostics for plugin self-updates
Why
The wpdeploy
update_queuetable had a 46% historical failure rate, but every single failure row stored the literal string"Installation failed"— collapsing every failure mode into one opaque error with no diagnostic value. Root cause: theinstall_update()method in both clients (AF auto-updater and wpd-client) treatedPlugin_Upgrader::upgrade()as a boolean, throwing awayWP_Errorobjects and skin-emitted error messages.Fixes (
inc/class-auto-updater.phpinstall_update())- Refreshes the
update_pluginstransient before invoking the upgrader. The upgrader reads from this transient to know what version to download; if WP hasn't checked recently, the upgrader silently returns false (looking like a failure even though there's a real update queued at wpdeploy). - Distinguishes
WP_Error,false/null, and success.WP_Errorwas previously treated as truthy → reported as "completed" even on failure. Now extracts the error code and message. - Reads
Automatic_Upgrader_Skin::get_errors()to surface the real upgrader-emitted error messages. - Reads
$upgrader->resultwhich holds the finalWP_Errorfor some failure paths. - Captures PHP errors/warnings emitted during the upgrade (file-move issues, etc.) via a temporary
set_error_handler. - Detects "no update in transient" as a distinct failure cause and labels it explicitly so we know it's a transient-cache problem, not an actual install failure.
- Truncates the combined diagnostic to 1000 chars before sending.
The same fix is applied to
wpd-client.php(the WPD client plugin shipped fromclient-plugin/wpd-client.phpon the wpdeploy server).Files Changed
- Modified:
auctionforge.php,inc/class-auto-updater.php
---
[3.6.2.4] — 2026-04-30
Bulk-sync worker dispatch fix
Fixes
- The HTTP-loopback worker (
auctionforge_rest_sync_workerinauctionforge.php) had its own switch statement for job-type dispatch, distinct from the one incrontasks/syncWorker.php. The newfull_sync_upcomingandfull_sync_pastjob types were only added to the CLI worker, so the loopback path produced "Unknown job type" errors. Both switches now route those types toBulkSyncWorker::process. inc/coreIncludes.phpnowrequire_oncesBulkSyncWorker.phpso the class is available wherever sync code runs.
Files Changed
- Modified:
auctionforge.php,inc/coreIncludes.php
---
[3.6.2.3] — 2026-04-30
Fixes for end-to-end Telegram round-trip
Fixes
verify_api_keyreads the option fresh on every call (hash_equalsagainstget_option('auctionforge_update_api_key')) instead of relying on the cached$this->api_keyfrom constructor time. Different FPM workers can hold different cached values when the option drifts (e.g. via auto-heal collisions), which previously produced intermittent 401s on REST endpoints.- New REST endpoint
POST /wp-json/auctionforge/v1/sync/version— wraps the existingtrigger-installflow with a JSON response (always HTTP 200 withsuccessflag). The original endpoint returnedWP_Error('no_update', …, status: 404)when the plugin was already on the latest version, which nginx'serror_page 404directive then clobbered with a static HTML 404 page on hosts using aaPanel/BTWAF. Keeping the URL under/sync/*matches the pattern that's already proven to pass through host WAFs.
Files Changed
- Modified:
auctionforge.php,inc/class-auto-updater.php
---
[3.6.2.2] — 2026-04-29
Catalog-sync kind disambiguation
Fix
catalog_syncjobs target a single auction that may be either active or archived. Until now their alerts were always classified askind=upcoming. The classifier now resolves the auction'sauction_stateterm meta and routes:ARCHIVED/ENDED/POST_AUCTION→kind=past→ Kill + Full Past buttons- anything else (or unresolvable) →
kind=upcoming→ Kill + Full Upcoming buttons
Files Changed
- Modified:
auctionforge.php,inc/class-auto-updater.php
---
[3.6.2.1] — 2026-04-29
Telegram Sync Monitoring follow-ups
Features
- Context-aware alert buttons. Each Telegram alert now shows the action set most relevant to the failing sync: upcoming-sync errors get Kill + Full Upcoming, past-sync errors get Kill + Full Past, everything else gets Kill only. Button choice is driven by a new
kindfield classified at log-write time from the queue'sjob_type. - Plugin version in alerts + Update button. Each push now includes the live
plugin_version. wpdeploy compares it to the latestis_stable=1row in itsversionstable and only renders an Update plugin button when the site is behind. Tapping Update calls the existingPOST /wp-json/auctionforge/v1/trigger-installendpoint to force the upgrade.
Architecture
- New private helper
AuctionForge_Auto_Updater::classify_error_kind($jobId)looks up the job'sjob_typeand maps it to'upcoming'/'past'/'other'. Used by both the immediate push and the 1-min retry cron. - Outbound payloads now include
plugin_versionat the top level; wpdeploy refreshessites.plugin_versionon every/sync-errorsPOST.
Files Changed
- Modified:
auctionforge.php,inc/class-auto-updater.php
---
[3.6.2.0] — 2026-04-29
Telegram Sync Monitoring & Remote Control
Features
- Instant Telegram alerts on sync errors. Any
level='error'row written toaf_sync_logis pushed (fire-and-forget, non-blocking) to wpdeploy, which fans it out to a configured Telegram group with inline-keyboard action buttons (Kill / Full Upcoming / Full Past / Acknowledge). - Remote command surface. Any group admin can tap a button to:
- Kill sync — flips DB flags via
SyncQueue::cancelAll(), then SIGTERMs every active worker; a 5-second watchdog escalates to SIGKILL for any survivor. - Full sync upcoming — full re-import of every active auction and its lots (queued, observable, killable). Replaces the
re-sync?do=importBidSpiritUpcomingflow with a queued equivalent. - Full sync past — same, for archived auctions.
- Safety-net retry cron (
auctionforge_retry_sync_errors, every minute) re-pushes recent error rows. wpdeploy dedupes viaUNIQUE(site_id, af_log_id)so duplicates are silent.
Architecture
SyncLogger::log()now firesdo_action('auctionforge_sync_error_logged', …)onlevel='error'so any handler can react. The auto-updater listener does a 2 s non-blocking POST to/api.php/sync-errors.- New REST endpoint
POST /wp-json/auctionforge/v1/sync/cancel-all(X-API-Key auth) — runsSyncQueue::cancelAll()+ SIGTERM + watchdog. Logs every action throughSyncLogger. POST /sync/startextended with amodeparameter (upcomingdefault,pastfor archived). Bulk re-sync is now a queued job, not a synchronous block.- New job types
full_sync_upcomingandfull_sync_pastonSyncQueue, dispatched to a newBulkSyncWorkerthat wraps the existingAuctionList::init()+LotList::init($upcoming)pipeline. syncWorker.phpinstalls a SIGTERM handler that flips the in-flight job tofailedwith a "Killed by admin (SIGTERM, cleanup OK)" marker and closes the DB cleanly before exiting. Watchdog escalates to SIGKILL after 5 s grace.LotList::auctionProcessing()now heartbeats the active bulk-sync job between auctions, preventing the safety cron from auto-failing long bulk runs as stale (the 600 s threshold is unchanged).
Files Changed
- Modified:
auctionforge.php,inc/sync/SyncLogger.php,inc/sync/SyncQueue.php,inc/class-auto-updater.php,crontasks/syncWorker.php,inc/import/LotList.php - Created:
inc/sync/BulkSyncWorker.php
---
[3.6.1.6] — 2026-04-29
High-Value Lot Modes for
[bp_lot_list]Features
high_value_pastmode — Displays past auction lots ordered by their catalog estimate (estimatedPriceInt), highest first. Useful for "Top Lots" or "Highlights" sections.high_value_soldmode — Displays past sold lots ordered by their actual sold price (soldBid), highest first. Only includes genuinely sold lots (soldBid > 0) and reuses the same false-positive guard asrandom_pastto skip lots wheresoldBidwas carried over fromstartPricewithout real bidding activity.- Admin documentation updated — The Shortcodes reference page in WP Admin now lists both new modes in the
modeattribute description and includes example shortcode usage.
Architecture
- New constants
MODE_HIGH_VALUE_PASTandMODE_HIGH_VALUE_SOLDonLotsWidget. - New method
LotsWidget::getLotListHighValue($mode, $limit)builds the query, applies the past-auction tax filter, setsbp_orderbyto the relevant meta field withDESCorder, and (for the sold variant) filters out unsold-but-stale lots in PHP. - New filter hook
bp_lot_list_high_value_args_filterfor downstream customization of the WP_Query args.
Files Changed
- Modified:
inc/widgets/LotsWidget.php,inc/controllers/ShortcodesPage.php
---
[3.6.0.18] — 2026-04-25
Brevo SMS Notifications Integration
Features
- Transactional SMS via Brevo API — The plugin now sends text message alerts through the Brevo transactional SMS service, running alongside existing Firebase push notifications.
- Four Notification Types:
- New Auction Published — Broadcast SMS to all opted-in subscribers when an auction is published.
- Auction Starting Soon — Targeted SMS to users registered for an auction when it is about to start.
- Favorited Item Live Soon — Targeted SMS to users who favorited a lot when it is approaching in the auction.
- Outbid Notice — SMS sent when a user's leading bid is surpassed, with a 5-minute per-item cooldown to prevent spam.
- SMS Subscriber Database — New
af_sms_subscriberstable stores user phone numbers, country codes, and per-notification-type opt-in preferences (GDPR-ready explicit consent). - Admin Settings Tab — New "SMS Notifications" tab in Settings with:
- Brevo API Key input
- SMS Sender Name (11 char max)
- Master enable/disable toggle
- Per-notification-type on/off switches
- Test SMS widget with phone input and send button
- Live subscriber count display
- Profile SMS Preferences — Users can opt into SMS notifications directly from their profile page with phone number entry and granular notification type selection.
Architecture
- BrevoSMS Service (
inc/services/BrevoSMS.php) — cURL-based API wrapper with broadcast, targeted, and single-send methods, message builders with 160-char limit awareness, rate limiting, and comprehensive error logging. - SMSSubscriber Model (
inc/model/SMSSubscriber.php) — CRUD operations, email-to-phone resolution, opt-in filtering, and upsert logic. - Webhook Integration — SMS dispatch hooks added to
AuctionsAPI.phpmethods:leading_bid_surpassed(),item_live_soon(),auction_starts_soon(), andauctionPublishedPush().
AJAX Handlers
auctionforge_sms_save— Save SMS preferences from profile pageauctionforge_sms_load— Load SMS preferences for profile pageauctionforge_sms_test— Admin-only test SMS endpoint
Database
- New table:
af_sms_subscribers— Phone numbers, country codes, per-notification opt-ins, timestamps
Files Changed
- Modified:
auctionforge.php,inc/coreIncludes.php,inc/controllers/AuctionsAPI.php,inc/controllers/Settings.php,admin/view/settings.php,templates/parts/profile-templates.php - Created:
inc/services/BrevoSMS.php,inc/model/SMSSubscriber.php
---
[3.6.0.7] — 2026-04-14
Hotfix
Fixes
- Namespace resolution — Fixed fatal error in
wp_footercommission label hook caused by unqualifiedSettingsHelperandSettingsclass references. Now uses fully qualified namespaces.
Files Changed
- Modified:
auctionforge.php
---
[3.6.0.6] — 2026-04-14
Commission Label Override Fix
Fixes
- Theme template override compatibility — Moved the commission label JS override from the
single-lot.phptemplate intoauctionforge.phpviawp_footerhook (priority 99). Sites with theme-level template overrides (e.g.themes/*/auctionforge/single-lot.php) were not picking up the inline script. Thewp_footerapproach works universally on all single lot pages.
Files Changed
- Modified:
auctionforge.php,templates/single-lot.php
---
[3.6.0.5] — 2026-04-14
Commission Label Override
Features
- Commission Label Setting — New dropdown in Settings → Appearance allowing admins to choose between "Buyer's Premium" (default) and "Auction House Commission" as the label displayed on lot pages. This overrides the Bidspirit JS client's default label using a MutationObserver that catches asynchronously injected text.
Files Changed
- Modified:
inc/controllers/Settings.php,templates/single-lot.php
---
[3.6.0.4] — 2026-04-12
Auction Approval Modal Redesign
Changes
- Removed BidSpirit Terms of Use — The generic BidSpirit "Terms of Use" section that appeared at the top of the non-credit-card approval modal has been removed. The modal now shows only the auction house's own legal agreements managed within the plugin.
- Renamed Modal Title — Changed "Terms of conditions" to "Terms & Conditions".
- Larger Scroll Area — The Terms & Conditions scroll box is now 350px tall (up from 200px) for easier reading.
- Proportional Section Heights — Refund & Return Policy and Chargeback Waiver sections use a shorter 260px scroll box to visually distinguish them from the primary Terms & Conditions.
Files Changed
- Modified:
templates/js-chunks/approval-info.php,assets/js/app.js
---
[3.6.0.2] — 2026-04-10
Webhook Token Generator
Features
- Token Generator Widget — Added a 16-character random token generator directly below the "Webhook auth token" field on the Settings page. Includes a "Generate Token" button and a clipboard copy icon with visual feedback.
Files Changed
- Modified:
inc/controllers/Settings.php
---
[3.6.0.1] — 2026-04-10
Patch
Changes
- Version bump.
---
[3.6.0.0] — 2026-04-10
Legal Agreements for Auction Approval
Features
- Terms & Conditions — A mandatory, scrollable Terms & Conditions document is now displayed during the auction approval process. Bidders must scroll to the bottom and check an agreement box before their approval request is submitted. Always enabled.
- Refund & Return Policy — An optional, scrollable Refund & Return Policy can be enabled in Settings. When enabled, bidders must read and accept it during auction approval.
- Chargeback Waiver — An optional, scrollable Chargeback Waiver can be enabled in Settings. When enabled, bidders must read and accept it during auction approval.
- Admin Management — New "Legal Agreements" page under the Bidspirit admin menu with tabbed TinyMCE editors for each agreement type. Includes automatic version numbering (incremented on content change) and full version history.
- Consent Logging — Every agreement acceptance is logged to a dedicated database table (
af_user_agreement_log) with the agreement type, version, user email, IP address, user agent, auction ID, and timestamp. - User Tracking Integration — Agreement events (
terms_agreement,refund_agreement,chargeback_waiver) are also recorded in the existing IP tracking system alongside registration, login, and bid events. - Placeholder Content — Default sample content is seeded on plugin activation for all three agreement types.
Settings Added
- Enable Refund & Return Policy — Toggle to require bidders to accept the refund policy during auction approval.
- Enable Chargeback Waiver — Toggle to require bidders to accept the chargeback waiver during auction approval.
Database
- New table:
af_legal_agreements— Current active agreement content per type - New table:
af_legal_agreement_versions— Version history archive - New table:
af_user_agreement_log— User consent records
Files Changed
- Modified:
auctionforge.php,inc/controllers/Settings.php,inc/controllers/BidspiritViews.php,inc/ip-logger.php,templates/js-chunks/approval-info.php,assets/js/app.js - Created:
inc/legal/class-legal-agreements.php,admin/view/legal-agreements.php
---
[3.5.0.6] — 2026-04-08
Bid Event Tracking
Features
- Bid Tracking — All successful bids (regular, catalog, pre-sale buyout, post-sale purchase) now fire
afLogIP("bid", bidspiritUser)to capture the bidder's full identity in the user tracking table. - Whitelist Update — Added
bidto the allowedevent_typevalues in both the local plugin and the central WPDeploy API.
---
[3.5.0.5] — 2026-04-08
Self-Healing Database Schema
Features
- Auto-Migration — The plugin now auto-detects and adds any missing tracking table columns on version upgrade, ensuring sites with older schemas seamlessly migrate without manual SQL.
---
[3.5.0.4] — 2026-04-08
API Key Auto-Healing
Features
- Seamless Self-Registration — The WordPress plugin now autonomously regenerates and saves a fresh API Key whenever WPDeploy rejects a payload with an
api_key_collisionerror. This guarantees zero-downtime security handovers when developers clone instances to proxy/staging servers.
---
[3.5.0.3] — 2026-04-08
API Key Collision Defense
Features
- 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_collisionerrors, directly instructing developers to update cloned keys.
---
[3.5.0.2] — 2026-04-08
Modal Trigger Hotfix
Fixes
- Restructured internal UI rendering priority to gracefully deploy the inline Modal triggers inside custom IP log view without colliding with cached
z-indexstacks.
---
[3.5.0.1] — 2026-04-08
Hotfix
Fixes
- Timed Auction Badge Visibility — Fixed a strict type-matching bug in the main
auction_list.phpcore file that incorrectly hid the "Timed Auction" badge overlay from valid timed/online auctions on the main upcoming/archive views. The badge now displays properly across all manual and Bidspirit-synced objects when toggled on.
Files Changed
- Modified:
templates/main/auction_list.php
---
[3.2.9.1] — 2026-03-30
Timed Auction Display Enhancements
Features
- Timed Auction Countdown Text Toggle — Added a WP-Admin setting "Change text to 'Auction will close in'" that conditionally changes the countdown label for timed/online auctions on single lot pages.
- Shortcode Text Toggle Support — Extended the new countdown text logic to the
bp_upcoming_wideshortcodes so "Live bidding starts in:" successfully transitions to "Auction will close in:" for timed auctions.
Files Changed
- Modified:
inc/controllers/Settings.php,templates/single-lot.php,templates/shortcodes/upcoming-auction-wide.php,templates/shortcodes/upcoming-auction-wide-manual.php
---
[3.2.9.0] — 2026-03-29
Billing & Invoices Polish
Fixes
- Profile Invoice ID Tracking — Prevented internal auction codes (e.g.
002orai4) from breaking into the clean hyphenated titles inside theprofile-templates.phpview. - Dynamic Payment Statuses — Replaced Bidspirit's default/cached
NOT PAIDHTML payloads by wiring thedompdfgenerator to directly respect the current$b.statusstring from the API (resolving instances where a paid invoice still printed "NOT PAID" atop the document). - Payment Instructions Conditional — Automatically hide the "Payment Instructions" block from the PDF footer when an invoice is fully paid.
- Improved Nomenclature — Changed "Invoice No:" to "Bidder No:" on document output to prevent confusion with static invoice ledger IDs.
---
[3.2.6.0] — 2026-03-28
Multi-Day Auction Lot Filtering Fix
Fixes
- Day 2+ showing lots from Day 1 in multi-day auctions — The
itemIndexcolumn inbp_meta_dataisvarchar(55), but the day-range filter inBidspiritQuery::bp_query_where()was comparing it as a string. With string comparison, lot numbers like'11','101'–'145'incorrectly fell between'1001'and'1450', causing Day 1 lots to leak into Day 2 results. Fixed by usingCAST(bpMeta.itemIndex AS UNSIGNED)for numeric comparison andintval()on the PHP-side boundary values. Letter lots (e.g.14A,1025A) are handled correctly —CASTstrips the suffix, keeping them grouped with their base lot number.
Files Changed
- Modified:
inc/controllers/BidspiritQuery.php
---
[3.2.5.9] — 2026-03-27
Catalog Page Fix
Fixes
- Duplicate preview hours on catalog pages — The
displayHoursfield was rendered twice: once via thebp_after_description_auctionhook inBidspiritViews.phpand once inline in the auction template. Removed the hook-based rendering to eliminate the duplication.
Files Changed
- Modified:
inc/controllers/BidspiritViews.php,templates/main/auction.php
---
[3.2.5] — 2026-03-19
Sync Reliability & Stuck Lot Prevention
Fixes
- CATALOG_PUBLISHED webhook now triggers catalog sync — Previously only sent push notifications without syncing lots. When the earlier AUCTION_CATALOG_UPDATED fired before the catalog was ready on BidSpirit, lots were never imported. CATALOG_PUBLISHED now calls
auctionCatalogUpdated()to trigger a full catalog sync when the catalog is actually available. - 0-lot API results now fail instead of silently succeeding — When BidSpirit API returns 0 lots (catalog not yet ready), the sync job now fails with an explicit error message, allowing the next webhook to create a fresh retry job.
- Expanded CDN allowlist in pre_http_request filter — The HTTP filter during bulk post insertion now allows all
*.bidspirit.comsubdomains and BidSpirit image CDNs (fastly.net,cloudfront.net). Previously onlybidspirit.comandwww.bidspirit.comwere allowed, blocking image downloads during sync and causing worker hangs. - InsertLotsBS timeout guard — Stage 5 (InsertLotsBS processing loop) now has a 180-second timeout and logs progress every 2 batches. Prevents indefinite hangs that previously required manual force-kill.
- fixResult() no longer marks lots as done when postId=0 — When
lotProcessing()fails to create a WP post, the staging row now keepssyncFinished=0so the lot is retried on the next sync pass, instead of being permanently marked as complete with no actual post. - lotProcessing() logs error on missing auction term — Previously returned 0 silently when
Auction::findAuctionById()failed. Now logs an explicit error that feeds intofixResult()to keep the lot retryable. - Hourly orphan detection in safety cron — New step in
syncSafety.phpdetects lot posts that exist inbp_meta_databut are missing their auction taxonomy assignment (caused by workers killed mid-batch) and auto-repairs them withwp_set_object_terms().
Files Changed
- Modified:
inc/controllers/AuctionsAPI.php,inc/sync/CatalogSyncWorker.php,inc/abs/InsertLotsAbstract.php,inc/import/InsertLotsBS.php,crontasks/syncSafety.php
---
[3.2.4] — 2026-03-18
Sync Worker Hang Fix
Fixes
- Sync workers hanging at InsertLotsBS stage — Third-party plugins (Smush Pro, SmartCrawl SEO, WPMU DEV Updates) hook into
wp_insert_post()and make blocking outbound HTTPS calls for every lot processed. With 489+ lots per auction, this caused workers to hang indefinitely on socket reads to WPMU DEV servers (32.193.94.25,32.193.93.106). AddedWP_IMPORTINGconstant at the REST worker entry point and apre_http_requestfilter inCatalogSyncWorkerthat blocks all non-essential external HTTP during the batch post-insertion phase. Loopback (127.0.0.1,localhost) and BidSpirit API calls remain allowed. - Stuck staging rows after force-kill — When workers were force-killed mid-sync, staging rows in
import_historywere left withsyncstart=1and never unblocked. Subsequent sync runs could not see these rows (filtered out byLot::getRawLots()), causing the InsertLotsBS loop to exit immediately with 0 posts processed. Combined with job deduplication (SyncQueue::enqueue()skips if aprocessingjob exists), this created a deadlock where no new sync could proceed.
Files Changed
- Modified:
auctionforge.php,inc/sync/CatalogSyncWorker.php
---
[3.2.2] — 2026-03-17
Full Sync Auction Discovery Fix
Fixes
- Full Sync finds no auctions on fresh sites — The v3
full_syncaction only queried the WordPress database for existing auction terms, but on a freshly deployed site the database has zero auctions. AddedAuctionList::init()discovery step before querying the DB, so Full Sync now fetches all auctions from the BidSpirit API and creates taxonomy terms first, then enqueues catalog sync jobs for each.
Files Changed
- Modified:
auctionforge.php
---
[3.2.0] — 2026-03-14
Webhook Pipeline Fixes, Archive Sync & Admin UI Overhaul
New Features
- Archive Sync — New "Archive Sync" button on Sync Status admin page. Enqueues catalog sync jobs for all ARCHIVED/ENDED auctions. Past auctions now appear in the auction dropdown with an optgroup separator and state label.
- Sync Tasks v3 — Replaced old v2 task cards (importData, importBidSpirit, lotBidSpiritOld) with v3 queue-based tasks. "Sync Active Auctions" and "Sync Archived Auctions" now enqueue jobs via the queue system. Maintenance tasks (Clean Draft/Trash Lots, Clean Orphaned Meta) remain as direct-execution tasks.
- How It Works guide rewritten — Complete rewrite of the admin guide for v3 architecture. Documents webhook-first flow, all 5 job types, queue system mechanics, cron setup (external + WP-Cron), configuration constants, and troubleshooting.
Fixes
- Dual-write removed — Removed legacy handlers from
auctionCatalogUpdated(),auctionDayEnded(), anditemsUpdated()webhook methods. The old handlers were racing with the v3 worker, creating orphaned staging rows inimport_historythat were never processed. All three methods now exclusively use the v3 enqueue → spawn path. - ITEMS_UPDATED webhook — Fixed
itemsUpdated()failing to enqueue jobs. TheITEMS_UPDATEDpayload hasauctionIdnested initemsByLanguage.{lang}[0].item.auctionId, not at the top level. Added extraction logic to resolve it. - ItemUpdateWorker incomplete —
ItemUpdateWorker::process()was only callingLot::bulkSave()(staging table) without runningInsertLotsBSto process staged data into WP posts andbp_meta_data. Added the InsertLotsBS processing step with autocommit restore. Item updates now flow: stage → InsertLotsBS → WP post + meta → cache clear. - Worker spawn reliability — Changed
SyncQueue::spawnWorker()from non-blocking HTTPS to blocking HTTP loopback (http://127.0.0.1with explicitHostheader, 2s timeout). Fixes nginx 403/404 errors when HTTPS loopback hits the default vhost instead of the site's vhost. - API token constant — Plugin expects
AUCTIONFORGE_API_TOKENinwp-config.php(renamed fromUCO_API_TOKENduring the plugin rename). Documented in readme.
Database
- DB version: 22 → 23
Files Changed
- Modified:
inc/controllers/AuctionsAPI.php,inc/sync/ItemUpdateWorker.php,inc/sync/SyncQueue.php,auctionforge.php,admin/view/sync-status.php,readme.txt
---
[3.0.0] — 2025-03-14
New Feature: Webhook-First Sync Architecture (Sync v3)
Overview: Complete redesign of the BidSpirit data synchronisation pipeline. Replaces the old two-phase polling system (importBidSpirit every hour + importData every minute) with a webhook-driven job queue that processes data in near real-time.
Architecture
- 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: webhook → queue → background worker → WordPress posts. - Dual-write mode — During transition, webhooks enqueue jobs AND still run the legacy handlers. Once verified, legacy handlers can be removed cleanly.
- Job deduplication — Prevents duplicate work by checking for existing pending/processing jobs with the same auction_id + job_type.
New Components
- Job Queue System (
inc/sync/SyncQueue.php) — Priority-based FIFO queue with atomic job claiming, status tracking (pending/processing/completed/failed/skipped), worker PID tracking, and automatic stuck job recovery. - Sync Logger (
inc/sync/SyncLogger.php) — Real-time log table for admin console polling with level filtering (info/success/warning/error) and incremental cursor-based retrieval. - Catalog Sync Worker (
inc/sync/CatalogSyncWorker.php) — Processes catalog_sync, full_sync, and day_ended jobs by reusing existingLotList::singleRun()logic. - Item Update Worker (
inc/sync/ItemUpdateWorker.php) — Processes individual item_update jobs with the same logic as the webhookitemsUpdatedhandler. - Background Worker (
crontasks/syncWorker.php) — Async CLI process spawned by webhooks viaexec()or by the safety cron. Claims and processes queued jobs with a configurable timeout (default 240s). - Safety Net (
crontasks/syncSafety.php) — Hourly cron that resets stuck jobs (>10min), spawns workers for pending jobs, runs a 24-hour health check (auto-enqueues full sync if no webhooks received), and purges old data.
Admin UI
- Queue Status Dashboard — New card on Sync Status page showing pending/processing/completed/failed/skipped counts, recent jobs table with real-time refresh, worker status badge, and action buttons:
- Full Sync — Enqueues catalog sync for all active auctions
- Sync Selected — Enqueue a single auction from dropdown
- Spawn Worker — Manually trigger a background worker process
- Live Console — Dark-themed terminal console on the Sync Status page. Polls
af_sync_logevery 1.5s showing timestamped, color-coded log entries from webhooks, workers, queue operations, and the safety cron. Supports pause, clear, and auto-scroll.
Cron Changes
- Removed
importData(ran every minute — ~1,440 PHP executions/day) - Removed
importBidSpirit(ran hourly — ~24 PHP executions/day) - Added
syncSafety(runs hourly at :10 — 24 PHP executions/day) - Net effect: ~62 PHP executions/hour → 1 PHP execution/hour
- WP-Cron safety hook (
auctionforge_sync_safety) — Always-active hourly event, independent of external cron - setup.sh v3 — Updated task definitions, new
migratecommand for interactive v2→v3 transition
Database
- New table:
af_sync_queue— Job queue with status, priority, source, attempts, worker PID, timing columns - New table:
af_sync_log— Real-time log entries with context, level, auction_id, job_id - DB version: 20 → 22
Constants Added
| Constant | Default | Description |
|---|---|---|
|
AUCTIONFORGE_SYNC_WORKER_TIMEOUT| 240 | Worker process timeout in seconds ||
AUCTIONFORGE_SYNC_STALE_JOB| 600 | Seconds before a processing job is considered stuck ||
AUCTIONFORGE_SYNC_HEALTH_CHECK| 86400 | Seconds without webhook before triggering full sync ||
AUCTIONFORGE_SYNC_LOG_RETENTION| 7 | Days to keep log entries ||
AUCTIONFORGE_SYNC_QUEUE_RETENTION| 30 | Days to keep completed queue jobs ||
AUCTIONFORGE_CURL_TIMEOUT| 30 | BidSpirit API cURL timeout in seconds ||
AUCTIONFORGE_PHP_BINARY| /www/server/php/83/bin/php | PHP CLI binary path for spawning workers |AJAX Handlers Added
auctionforge_sync_log_poll— Incremental log polling for live consoleauctionforge_sync_queue_status— Queue counts + recent jobs for dashboardauctionforge_sync_enqueue— Admin-triggered sync actions (full_sync, sync_auction, spawn_worker)
Fixes
- cURL timeout — BidSpiritRequest now enforces a 30-second timeout (was unlimited/0), preventing hung connections from blocking the sync pipeline.
Files Changed
- Modified:
auctionforge.php,inc/coreIncludes.php,inc/controllers/AuctionsAPI.php,inc/BidSpiritRequest.php,admin/view/sync-status.php,crontasks/setup.sh - Created:
inc/sync/SyncQueue.php,inc/sync/SyncLogger.php,inc/sync/CatalogSyncWorker.php,inc/sync/ItemUpdateWorker.php,crontasks/syncWorker.php,crontasks/syncSafety.php
---
[2.7.3.0]
Fixes
- Various stability improvements and bug fixes.
[2.7.1.2]
Fixes
- Added missing
vatAndCommission()function inloadBid()— the sales tax display on single lot pages was never being rendered because the code to callloadTemplateforvat-and-commission-templatewas missing fromapp.js.
[2.7.1.1]
Fixes
- 2 decimal places now only appear in the bid modal (Your max bid, Total Price) via
showDecimalsflag. 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.
[2.7.0.9]
Fixes
- Fixed fatal error during plugin install/upgrade:
class-stats-database.phprequire failure.
[2.7.0.0]
New Features: Advanced Lot Analytics
- Conversion Tracking, Peak Viewing Times, Pre-Sale vs Live Comparison, Category Performance, Share Analytics, Search → View Funnel, Click-Through Tracking, CSV Export, Hot Lot Badge.
- New DB table:
af_lot_shares. New columns onaf_lot_analytics. DB version bumped to 20.
[2.6.0.0]
New Feature: Lot Analytics
- Comprehensive lot view and favorite tracking system with admin dashboard.
[2.5.0.0]
New Features
- Site Statistics System — Full website analytics built into the plugin admin.
- Recently Viewed Items — Profile page tab showing last 20 viewed lots per user.
- Run Identity Check — calls the new wpdeploy
-
v3.7.0.24 Stable May 07, 2026Download v3.7.0.24📦 9 MB⚙️ WP 5.2+🔧 PHP 7.2+✓ Tested 6.4
AuctionForge Changelog
All notable changes to the AuctionForge plugin are documented in this file.
---
[3.7.0.21] — 2026-05-05
Added — Connection Diagnostics on the Updates admin page
A new Connection Diagnostics card on Lots → Updates that detects and one-click-heals identity mismatches between this site and the deployment server.
The problem it solves. When a WordPress install is cloned (template → customer site, dev → prod, backup → restore), the cloned wp_options carry the original site's
auctionforge_update_api_keyover to the newhome_url(). The new install then makes API calls to wpdeploy *authenticated as the original site*. wpdeploy looks up by api_key, not by URL, so every/sync-user-tracking,/check-updates,/report-health, and most importantly the Kuma push URL, gets recorded against the WRONGwpdeploy.sitesrow. The cloned site's monitor stays silent; the original's monitor shows traffic that isn't from it.What the diagnostic does:
- Run Identity Check — calls the new wpdeploy
GET /api.php/whoamiendpoint and compares the returnedcaller_site_urlagainsthome_url(). Renders a verdict ("matches" / "MISMATCH") plus the full server-side view (site_id, site_name, last_check, plugin version on file, remote IP). The "Re-register & Reset Kuma" button only appears if there's a mismatch. - Re-register & Reset Kuma — calls
/request-access(which is idempotent onsite_url— wpdeploy returns the canonical api_key for *this*home_url(), regardless of whatever wrong key we were holding), wipesauctionforge_kuma_push_urland any leftover heartbeat cron events, then immediately fires/check-updatesso the api_request interceptor catches the freshly-correct kuma_push_url for *this* site. The keepalive mu-plugin's heartbeat picks it up on the next 60s tick.
Internal
AuctionForge_Auto_Updater::whoami()(new) — thin wrapper overapi_request('whoami', [], 'GET'). Returns the parsed wpdeploy/whoamipayload.AuctionForge_Auto_Updater::reset_connection()(new) — three-step heal: re-register → wipe Kuma cached state → re-fetch via/check-updates. Returns shape suitable forwp_send_json_success.- Two new AJAX actions:
auctionforge_diagnose_connection,auctionforge_fix_connection. Both behindmanage_optionscapability + nonce check. auctionforge_normalize_host()helper for case/scheme/www-tolerant URL comparison.
Server-side companion
Requires the wpdeploy
/api.php/whoamiendpoint added in the same release window. The endpoint is gated behind whatever api_key the caller already presented (a master key returnstype=masterwith no site row; a per-site key returns the site row that key resolves to). Reveals nothing the caller doesn't already implicitly authenticate against.---
[3.7.0.20] — 2026-05-04
Changed
- Kuma heartbeat path is now wpdeploy-independent. The actual heartbeat firing — wp-cron schedule, page-load piggy-back, outbound HTTP — moved out of AF and into the AuctionForge Keepalive mu-plugin (
wp-content/mu-plugins/auctionforge-keepalive.php, bumped to v1.2.1). Once a site has been provisioned once andauctionforge_kuma_push_urlis cached locally, the heartbeat keeps reporting forever even if AF is deactivated, mid-upgrade, deleted from disk, or wpdeploy is offline. The mu-plugin can't be deactivated by WordPress, can't be broken by an AF release, and depends on AF for nothing. - AF only writes the
kuma_push_urloption now. It no longer schedules the cron, no longer fires the heartbeat, and no longer holds any heartbeat-related state. Theapi_request()interceptor still catcheskuma_push_urlfrom/check-updatesand/report-healthresponses and persists it; the mu-plugin reads it from there. - Migration block.
init_hooks()clears any leftoverauctionforge_kuma_heartbeatwp-cron event from AF ≤ 3.7.0.19 on first plugin load after upgrade. The mu-plugin runs the same clear on its ownplugins_loadedhook — belt and braces. The new event the mu-plugin schedules iskuma_heartbeat_tickon a newkuma_60sschedule. AuctionForge_Auto_Updater::kuma_heartbeat()no-opped. Kept as a safety landing pad so any staleauctionforge_kuma_heartbeatwp-cron event that fires one last time before migration kicks in doesn't trip a "no callback registered" warning. Real heartbeat work happens in the mu-plugin.
Added — operator override
AUCTIONFORGE_KUMA_PUSH_URLconstant. Define it inwp-config.phpto point a site directly at Kuma without ever involving wpdeploy:
```php
define('AUCTIONFORGE_KUMA_PUSH_URL', 'https://kuma.example.com/api/push/<token>?status=up&msg=&ping=');
```
The constant takes precedence over the
auctionforge_kuma_push_urloption. With it set, the site can be operated fully outside wpdeploy — useful for one-off installs, customer-managed sites, or disaster-recovery scenarios where wpdeploy is unreachable for an extended period.Internal — Keepalive mu-plugin v1.2.1
The bundled keepalive template at
inc/keepalive/auctionforge-keepalive.template.phpnow also handles Kuma heartbeats. Three layered triggers ensure cadence stays tight regardless of site traffic:1. Dedicated wp-cron event
kuma_heartbeat_tickon a new 60-secondkuma_60sschedule2. Page-load piggy-back on
init: any request older than 50s since the last beat fires another, transient-guarded so concurrent hits coalesce. Free on busy sites; rescues low-traffic sites the moment any visitor arrives.3. Self-heal inside the cron callback: if the event somehow gets cleared, re-arm it before sending the beat.
HTTP is
timeout=2, blocking=false— fire-and-forget, never slows page loads. External IP introspection (ipify → ifconfig.me → icanhazip fallback chain, 24h transient cache) is duplicated in the mu-plugin so it doesn't depend on AF being loaded for the IP lookup.The keepalive installer (
class-keepalive-installer.php) detects theKEEPALIVE_VERSION: 1.2.1header bump and idempotently overwrites every site's mu-plugin on the next AF load. No manual reactivation needed.Failure modes after this release
| State | Heartbeat? |
|---|---|
| AF active and healthy | ✅ via mu-plugin |
| AF deactivated by an operator | ✅ mu-plugin runs anyway |
| AF deleted from disk | ✅ as long as
auctionforge_kuma_push_urloption exists OR constant is set || AF mid-upgrade / partial install | ✅ mu-plugin doesn't depend on AF code paths |
| wpdeploy down (existing site) | ✅ option is cached locally, no wpdeploy round-trip |
| wpdeploy down (brand-new site, never provisioned) | ❌ first-time URL provisioning still needs wpdeploy. One-shot, accepted trade-off. |
| Site has zero traffic AND wp-cron isn't firing | ❌ truly nothing to trigger a beat. Mitigation is OS-level cron / DISABLE_WP_CRON, out of scope here. |
---
[3.7.0.19] — 2026-05-04
Changed
- Reverted Kuma heartbeat cadence: 3 min → 1 min.
auctionforge_kuma_heartbeatis back on thebp_minutelyschedule. With Kuma's 310s silence window, 60s cadence tolerates 4 missed wp-cron ticks before flipping a monitor red — the original "give-it-leeway" semantics. The 3-min cadence introduced in 3.7.0.18 was strictly less chatty but tighter (a single missed tick would trip Kuma), and the trade-off wasn't worth it operationally. - Migration block updated.
init_hooks()now detects any existing event scheduled on a non-bp_minutelycadence (e.g. thebp_3_minutelyset by 3.7.0.18) and re-schedules ontobp_minutely. Sites that took 3.7.0.18 roll back automatically on first plugin load after upgrade. - First-fire jitter narrowed back to 0–60s to match the new cadence.
Notes
- The
bp_3_minutelycron schedule registration inauctionforge.phpis kept (harmless; available for future use). Only the heartbeat scheduling sites have been reverted. - Apparent latency in Kuma flipping a monitor red after a real outage is governed by Kuma's per-monitor
interval(silence-detection window, currently 310s on the wpdeploy/Kuma side), not by this cron's cadence. To detect outages faster, lower the Kumainterval; to add more tolerance to wp-cron drift, raise it.
---
[3.7.0.18] — 2026-05-04
Changed
- Kuma heartbeat cron cadence: 1 min → 3 min.
auctionforge_kuma_heartbeatnow runs on a newbp_3_minutelyschedule (180s) instead ofbp_minutely(60s). This pairs with Kuma's 310s silence-detection window — a single late wp-cron tick (3 min + drift) still lands inside the threshold, but normal traffic to Kuma drops by ~3×. - Random first-fire offset widened from 60s → 180s. With ~50 sites on a single Kuma instance, spreading first-fires across the full 3-min window prevents synchronised bursts every 3 minutes.
- Auto-migration of existing scheduled events. On plugin upgrade
init_hooks()callswp_get_scheduled_event('auctionforge_kuma_heartbeat')and, if the existing event is onbp_minutely, clears it and reschedules ontobp_3_minutely. Idempotent — a no-op once migrated.
Internal
- New cron schedule registered:
bp_3_minutely(BP_MINUTELY * 3= 180s). Defined alongside the existingbp_minutely/bp_ten_minutely/bp_hourly/bp_24_hourlyschedules inauctionforge.php.
---
[3.7.0.17] — 2026-05-04
Fix: "Install Now" always returned
up_to_dateThe
/sync/versionREST endpoint (called by wpdeploy's Install Now button) was always respondingsuccess: false, reason: up_to_dateregardless of the actual installed version, defeating the button's whole purpose.Root cause
rest_force_plugin_update()did:```
delete_site_transient('update_plugins');
$this->check_pending_updates();
$updates = get_site_transient('update_plugins');
```
check_pending_updates()calls the/pending-updatesendpoint on wpdeploy (which returns the deploy queue), but it does not touch the WPupdate_pluginstransient. The transient just got deleted on the line above and never gets re-populated, so theisset($updates->response[…])check always failed → always returnedup_to_date.Fix
- Use
wp_update_plugins()instead — that's what fires thepre_set_site_transient_update_pluginsfilter chain that AF's owncheck_for_updates()callback hooks into to seed the transient. Same pattern is already used correctly ininstall_update()at line 280. - Belt-and-braces: when the request body carries an explicit target
versionand that version is strictly greater than the on-disk plugin version (perversion_compare), bypass the transient check and force the install. This handles edge cases where the transient seeding fails (network blip during the wp-cron cycle, hosting-side cache, etc.) so the explicit Install Now command still does what it says.
---
[3.7.0.16] — 2026-05-04
Server external IP reported to wpdeploy + included in Kuma heartbeats
Each AF install now reports its server's outbound external IP. Two channels:
1. Kuma heartbeat
msg— the per-minute push payload now reads<wp_version>|<plugin_version>|<external_ip>(e.g.6.9.4|3.7.0.16|152.53.187.82) so you can spot at a glance which physical box each site lives on. When a host goes dark, multiple monitors flip red simultaneously with the same IP — instant root-cause hint.2.
/report-healthpayload — a newexternal_ipfield that wpdeploy stores onsites.external_ip. Visible in the Sites admin view as a tappable IP chip; clicking it filters the table to all sites sharing that IP.How the IP is detected
AuctionForge_Auto_Updater::get_external_ip()calls one of three public echo services in turn —api.ipify.org,ifconfig.me/ip,icanhazip.com— with a 4-second timeout each. The first one that returns a valid IP wins. Result is cached in a transient for 24 hours so we don't hit external services on every report cycle.Wpdeploy fallback for older plugins
/report-healthnow also capturesREMOTE_ADDR(orHTTP_CF_CONNECTING_IPwhen behind Cloudflare) when the payload doesn't includeexternal_ip. So sites still on 3.7.0.15 or older start populating their IP today via the same route, no plugin update needed for that data path.---
[3.7.0.15] — 2026-05-04
Kuma monitors land in an "Unallocated" group by default
New AuctionForge installs are auto-enrolled into Kuma under a new top-level group called Unallocated so the operator can review them and drag-drop into the right home (Bidspirit Auction Sites, Stephen's Auctions, Misc Websites, etc.) before classification. Without this every new monitor would appear at the dashboard top level alongside whatever group hierarchy already exists.
What changed (wpdeploy-side, no plugin behaviour change)
KumaProvisionernow ensures an "Unallocated" group exists in Kuma (find-or-create via the same Socket.IOaddpath used for monitors, withtype='group') before provisioning each new push monitor, and passesparent=<group_id>in theaddpayload so the new monitor lands inside it.- The Node helper accepts arbitrary
typeandparentfields on the input payload (previously hardcoded totype='push'). - The group itself gets the same
user_id=1reassignment so it shows up on the human admin's dashboard.
Existing Clumber monitor (id=71) was migrated into the new group as part of this release.
This is a wpdeploy infrastructure change — the AF plugin code is unchanged from 3.7.0.14. Version bumped only to mark a clean snapshot point.
---
[3.7.0.14] — 2026-05-04
Uptime Kuma push heartbeat with automatic enrolment
Each AF install now appears as its own monitor on the central Uptime Kuma at https://kuma.smoothbyteit.dev, beating every minute and flipping red within ~90 seconds when a site goes dark. Auto-enrolled — no manual Kuma UI clicks per site.
How it works
1. First contact: when the plugin calls
/request-accessor/report-health, wpdeploy's newKumaProvisioneropens a Socket.IO connection to Kuma as a dedicatedauctionforge-botuser, calls the officialaddevent, and gets back a fresh push token. The resulting URL is shipped to the plugin in the JSON response askuma_push_url.2. Plugin-side: a generic interceptor on
api_request()persistskuma_push_urlto the optionauctionforge_kuma_push_urlwhenever it appears in any wpdeploy response, and immediately schedules the newauctionforge_kuma_heartbeatcron on the existingbp_minutelyinterval.3. Heartbeat: the cron handler sends a single
wp_remote_getto the push URL each minute withmsg=<wp_version>|<plugin_version>so Kuma's dashboard shows the running stack at a glance. Kuma's silence-detection window is 90s, so a single missed wp-cron tick won't false-DOWN.4. Idempotency: the Kuma monitor's
descriptionfield storeswpdeploy_site_id:<id>. Re-registering the same site short-circuits at the wpdeploy layer (existingkuma_monitor_idonsites), or — if that's missing — Kuma's existing row is reattached via the description anchor. Re-installing the plugin never duplicates monitors.Why Socket.IO and not direct DB insert
Kuma's monitor scheduler does not poll its own DB for new rows —
startMonitors()only loads monitors at boot, and new ones are armed via the authenticated Socket.IOaddevent handler (which callsstartMonitor()and arms the per-monitorsafeBeatsetTimeout). A direct INSERT would create a "phantom" monitor that accepts pushes but never flips DOWN on silence, defeating the whole feature.Notifications + monitor ownership
Provisioner reads existing Kuma notification rows whose channel is Telegram (or marked default-for-new-monitors) and attaches them to every new monitor via the
addevent'snotificationIDList. After the Socket.IOaddsucceeds, the provisioner direct-writesuser_id=1to the new monitor row in Kuma's SQLite — Kuma'saddhandler hardcodesuser_id=socket.userID(the bot at user 2), which causes the frontend's real-time monitor-list updates to skip the admin's session. The follow-up UPDATE stamps ownership to the human admin so monitors render with their full name on the admin dashboard immediately.Failure modes
Every call boundary degrades safely. If Kuma is unreachable when a site registers, registration completes without
kuma_push_url; the next twicedaily/report-healthretries. Heartbeat HTTP failures are silent (which is the desired outcome — Kuma's silence-detection is the signal). Kuma reset / monitor row deleted: provisioner's pre-flight check NULLs the wpdeploy anchors and falls through to fresh provisioning on the next call.Operator setup
Already done: the
auctionforge-botKuma user has been created and credentials populated in wpdeploy'sconfig.php. To rotate or migrate Kuma later, editKUMA_URL/KUMA_BOT_USER/KUMA_BOT_PASSinconfig.php— no plugin redeploy needed.---
[3.7.0.13] — 2026-05-04
Wide shortcode: hide Register button for logged-in users
- When a user is logged in to BidSpirit (
body.bp-login), the Register button is now automatically hidden on wide-format auction cards (bp_upcoming_wideandbp_auction_list layout="wide"). - The View Catalog / Catalog Coming Soon button expands to full width when the Register button is hidden.
- Uses a lightweight
MutationObserverto react to BidSpirit's async session init. - Applied to both
UpcomingAuctionWide.phpandAuctionList.phpshortcode CSS blocks.
---
[3.7.0.12] — 2026-05-03
Stop-word denylist for BidSpirit category-tag concatenations
BidSpirit's
wp_bp_meta_data.tagsfield arrives as PascalCase category names lowercased without separators (uscollectibles,firearmsaccessoriesammunition,usdecorativearts,printsandmultiples). They look like keywords but they're really categories, and on sites where the tags field is populated they completely swamp the top-5 chips for power users (e.g. one buyer's profile was led byuscollectibles 453 viewsdespite that being a label rather than a real interest signal).29 known patterns added to
stop-words.phpso the tokenizer drops them at extraction time. New ones surfacing from sites we haven't seen yet should be added here as they appear; the wpdeploy?tab=keywordscorpus page makes them easy to spot (sort by most users with low lots count and look for non-word concatenations).---
[3.7.0.11] — 2026-05-03
Keyword extractor — capture model years + hyphenated calibers, drop more auction noise
The People view's top-5 keyword chips were filling up with generic descriptors (
household,model,original,assortment) instead of the brand/maker terms (mauser,whitworth,colt) that actually distinguish one buyer from another. Live-data review on the new?tab=keywordsKeyword Corpus page on wpdeploy confirmed the cause: real signal was being lost at the tokenizer stage.Tokenizer changes (
inc/stats/class-keyword-extractor.php)Three pre-passes now run before the standard split-on-non-alpha:
1. Hyphenated / x-separated calibers —
.45-70,.30-06,7.62x54r,8x57. Without this they're split into pure-digit fragments and dropped, losing the actual model identifier.2. Caliber-with-suffix —
9mm,.22lr,.45acp,.380acp. Previously only survived by accident because of the trailing letters; now extracted explicitly.3. 4-digit model years 1700–2099 —
1873,1903,1911,1971. Pure-digit tokens were unconditionally dropped; now retained when year-shaped.Standard pass relaxed to allow 4-digit pure-digit tokens between 1700 and 2099.
Stop-word additions (
inc/stats/stop-words.php)Conservative — only universally empty auction descriptors:
original,marked,accessories,decorative,household,goods,made,condition,assortmentDeliberately NOT added:
antique,vintage,rare,fine— those carry buyer-segmentation signal (antiquarian buyers vs. modern-collectibles buyers). Borderline cases (metal,wooden,american,model) are left to the wpdeploy-side IDF re-rank.Companion change on wpdeploy (no plugin update needed)
refresh_people_rollup.phpnow multiplies each keyword's score by an IDF factor pulled fromkeyword_idf(refreshed hourly byrefresh_lot_keyword_index.php). Generic keywords that appear in many lots get demoted automatically; brand/maker words that only appear on a handful get lifted into the top-5 chips.After deploying this version, reset the
auctionforge_lots_sync_watermarkoption on each site and clear thewp_af_stats_lot_keywordstable to force re-extraction of every lot through the new tokenizer.---
[3.7.0.10] — 2026-05-03
Lots sync — ship resolved CDN image URL, not bare BidSpirit filename
class-lots-sync.phpwas sendingimagesListStr's first comma-token verbatim asimage_url— that's the raw BidSpirit storage value (e.g.001.jpg). Wpdeploy received a bare filename, the browser resolved it against the wpdeploy host, and every lot thumbnail 404'd.The lots-sync now instantiates
LotImageand pulls the resolved CDN URL (LABEL_MEDIUMthumbnail), with fallback toLABEL_ORIGINALand a final defensive check that drops anything that doesn't start withhttp(s)://. Resolution is wrapped in try/catch — a missing class or BidSpirit settings issue leavesimage_urlempty rather than blowing up the sync batch.After deploying this version on a site, reset its
auctionforge_lots_sync_watermarkoption (delete the row) to re-push existing lots through the new resolver. The wpdeploy view skips<img>rendering whenimage_urlisn't a real URL, so dirty rows degrade silently while the watermark catches up.---
[3.7.0.9] — 2026-05-03
Keepalive sweep — auto-clears WP upgrader debris that produces silent "Could not create directory" failures
WordPress 6.x's atomic-rollback flow leaves
wp-content/upgrade-temp-backup/lying around when its post-install cleanup misfires (the user-facing symptom is "Update failed: Could not create directory" after an update that has actually already succeeded). Stalewp-content/upgrade/<plugin>-tmp/and.maintenancelockfiles from crashed upgrades cause the *next* upgrade attempt to fail the same way. None of WP's own scheduled cleanup catches these reliably.The keepalive mu-plugin (
KEEPALIVE_VERSION1.1.0) now sweeps all three classes of debris on every page load, transient-guarded to once per hour. Safety thresholds prevent it touching anything actually in flight:.maintenancefiles less than 5 min old,wp-content/upgrade/*entries less than 60 min old, andupgrade-temp-backup/less than 30 min old are left alone. Wrapped in try/catch with no throws, so the sweep can never block a request.The keepalive installer detects the version bump and rewrites
wp-content/mu-plugins/auctionforge-keepalive.phpautomatically on the next AF load, no manual reactivation needed.---
[3.7.0.8] — 2026-05-03
Shop auction UI refinements & share button settings
Shop (Buy-It-Now) catalog improvements
- Shop sorting dropdown: Added a dedicated sorting dropdown for shop catalogs with options: Recently Added, Price: High, and Price: Low. Sorts by
buyoutPricemetadata. Regular auction catalogs retain the original sorting options. - Removed "Buyout price:" label: On shop lot pages, the redundant "Buyout price:" text before the price is now hidden. Only the price and "Buy Now" button are displayed. Regular auction buyout lots still show the label.
- Removed increments table & terms links: On shop lot pages, the "Increments table" and "Terms and conditions" links are hidden since they don't apply to buy-it-now items. The "Make an inquiry" link remains.
Buyout confirmation modal overhaul
- Sales tax logic: The buyout confirmation modal now follows the same sales tax detection as the regular bid modal. When the auction house has a US state configured, displays "Sales Tax" instead of "VAT", with the correct percentage for same-state buyers and 0% for out-of-state.
- Hide 0% buyer's premium: The Buyer's Premium line is hidden when the commission is 0%.
- Shop-specific text: For shop buyouts, all disclaimer text is replaced with: *"You will receive an email with your invoice, including shipping, and a secure payment link."*
- Shop-specific buttons: "I don't Agree" → "Cancel", "I Agree" → "Buy". The "Terms of sale" button is removed for shop buyouts. Non-shop buyouts retain the original layout.
Purchase confirmed screen
- Title changed from "Confirm purchase:" to "Purchase Confirmed".
- Thank you message updated to: *"Thank you for your order. We will confirm your order within 1-2 business days and email you an invoice, including shipping, and a secure payment link."*
Share button settings (Appearance tab)
- Added a Share Buttons section to the BidSpirit Appearance settings tab with individual checkboxes for each sharing platform: Copy Link, WhatsApp, Facebook, Telegram, X (Twitter), VK, Pinterest, and Email.
- All platforms default to enabled (shown). Unchecking a platform hides that share button on all lot pages (both shop and regular auctions).
---
[3.7.0.7] — 2026-05-02
Identity stitch on bidder login — keyword interest tallying now actually fires
Why
The keyword extractor was filling
wp_af_stats_lot_keywordscorrectly (197 lots, 734 distinct keywords on Clumber), butwp_af_user_interestsandwp_af_user_recent_activitywere both empty — zero rows of any dimension. Same on every site running the new sync streams.Root cause: identity stitching (visitor_hash → email) only fired in the tracker AJAX when
is_user_logged_in()returned true. On these auction sites the actual bidders authenticate via BidSpirit, never aswp_users— so the WP login check was always false, the stitch table stayed empty, andmaybe_record_lot_view($url, $email, …)got called with an empty email and bailed out before tallying. Lot views by real bidders never landed in the user-side interest profile.What changed (no auth-path intervention)
The fix piggybacks on the *existing* fire-and-forget tracking AJAX that already runs after a successful BidSpirit login (
afLogIP("login", bidspiritUser)). It does not touch the BidSpirit auth path itself.inc/ip-logger.phpauctionforge_ajax_log_ip()— after the existingauctionforge_user_trackinginsert, if the request carries avisitor_hashand the email is valid, callsAF_Stats_Visitor_Email_Map::record($vh, $email, $ip). Wrapped in try/catch so any failure here can never break the existing tracking response.assets/js/app.js+src/js/app.jsafLogIP()— readslocalStorage['af_vid'](defensively, ITP/private-mode safe) and includes it asvisitor_hashin the POST body.inc/stats/class-stats-init.phpmaybe_record_lot_view()— when$emailis empty (the common case for BidSpirit-only bidders) but avisitor_hashis present, falls back toAF_Stats_Visitor_Email_Map::lookup($visitor_hash). If a stitch exists, the view tallies; if not, it stays anonymous.
Net effect: a bidder logs in (BidSpirit), the post-login tracker AJAX fires as it always has, and now also writes one extra row into
af_stats_visitor_emails. From that point onward, every page they view on the same browser/device tallies intoaf_user_interestskeyed on their email. The BidSpirit transaction itself is untouched.---
[3.7.0.6] — 2026-05-02
Critical fix —
X-API-Keyheader collision with sibling SmoothByte pluginsWhat was wrong
On any site running both AuctionForge and another SmoothByte-stack plugin that also points its updater at
wpdeploy.smoothbyteit.dev(e.g.seo-aeo-optimizer), the second plugin'shttp_request_argsfilter overwrote AuctionForge'sX-API-Keyheader on every outbound API call. Wpdeploy then 401'd because the key it received belonged to a different plugin instance — usually aseo_aeo_update_api_keythat wpdeploy had no record of.The symptom was a quiet, total auth failure:
report-health,check-updates, everysync-*route, all 401. The watchdog flagged streams as "gone" and updates stopped flowing. Affected sites: any install where the AuctionForge key and the sibling plugin's key happen to differ. Sites where both plugins shared a key were silently safe (the overwrite was a no-op).Fix
AuctionForge_Auto_Updater::add_download_auth()now refuses to clobber an existingX-API-Keyand, for download URLs, only stamps when the URL slug matches our own. That keeps targeted calls fromapi_request()intact regardless of filter ordering, and prevents either plugin from writing its key onto the other's download URL.The same fix has been applied to
seo-aeo-optimizerso both ends of the collision are defensive.---
[3.7.0.5] — 2026-05-02
Sync Status admin panel — diagnostic + manual triggers in wp-admin
Why
Diagnosing sync issues used to require shell access on the site or piecing together state from wpdeploy's app.log. This release surfaces the same diagnostics inside wp-admin so a site admin (or anyone with
manage_options) can see exactly what's happening and trigger fixes in one click.Lives inside the existing Sync Status menu (
Lots → Sync Status) — appended below the existing content as a "Sync Diagnostics & Manual Controls" section, no duplicate menu entry.What's on the panel
Connection summary — plugin version,
af_stats_db_version, wpdeploy server URL, last 8 chars of API key, keepalive install state + auto-reactivation count.Sync streams table — for each of the 10 cron hooks (user-tracking, user-profile, user-interests, user-activity, lots, bids+wins, vulnerabilities, report-health, check-updates, fraud-enforcement):
- Configured schedule
- Last fired timestamp + status colour-coded (green=success, blue=idle/empty, red=error)
- Record count from last run
- Next scheduled run
- Current watermark (where applicable)
- "Fire now" button — clears doing_cron, calls
do_action($hook)synchronously, shows the result
One-shot utilities
Test wpdeploy connection— calls/api.php/infowith the site's API keyClear stuck cron lock— deletes thedoing_crontransient (the classic fix when scheduled events stop firing)Reinstall keepalive— overwritesmu-plugins/auctionforge-keepalive.phpfrom the bundled templateBackfill bids from legacy tracking— replayslast_event_type='bid'rows fromwp_auctionforge_user_trackingintowp_af_bid_eventsso the bids-wins stream picks them up. Useful for sites that have years of bid history in the legacy table but nothing in the new queueRun all due events now— clears doing_cron and fires everyauctionforge_*cron event whose timestamp is past due, in one go
Live response output panel shows the JSON returned from each action so you can see what just happened without leaving the page.
Files Changed
- Created:
inc/admin/class-sync-status-page.php - Modified:
inc/stats/class-stats-init.php(load + init the panel) - Modified:
admin/view/sync-status.php(appendAF_Sync_Status_Page::render_panel()call at the bottom) - Modified:
auctionforge.php(Version 3.7.0.4 → 3.7.0.5)
Verification
Navigate to Lots → Sync Status in wp-admin on any 3.7.0.5 site. Scroll past the existing content to the new "Sync Diagnostics & Manual Controls" section. Click "Test wpdeploy connection" — you should see
{"success": true, "auth_type": "site"}. Click "Fire now" on any stream — the row's last-fired timestamp should refresh after 1–2 seconds.---
[3.7.0.4] — 2026-05-02
Self-healing: failed plugin updates can no longer take a site offline
Why
WordPress's plugin updater isn't transactional — when an update fails partway (corrupt unzip, fatal during the new version's
plugins_loaded, disk pressure, theme conflict, etc.) WP often deactivates the plugin and leaves the site without it. Once AuctionForge is dropped fromactive_plugins, no AF code runs again — including its sync handlers — until someone notices and reactivates manually. On the AuctionForge site fleet, this had quietly happened to ~5 sites we found; almost certainly more on production sites we don't have filesystem access to.This release ships an autonomous watchdog that lives outside the AuctionForge plugin entirely so it survives even when AF gets knocked out.
What changed
1. Self-installing keepalive (mu-plugin)
inc/keepalive/auctionforge-keepalive.template.php— a 50-line WordPress must-use plugin. Lives inwp-content/mu-plugins/, which WordPress can't deactivate. On everyplugins_loaded(priority 1, before any regular plugin), it checks: isauctionforge/auctionforge.phpon disk but missing fromactive_plugins? If yes AND the file has a validPlugin Name:header (smoke check — don't reactivate a corrupt zip), it re-adds AF andincludes the file in the same request.inc/keepalive/class-keepalive-installer.php— runs on every successful AF load. Copies the template intowp-content/mu-plugins/auctionforge-keepalive.phpif missing or version-bumped. Idempotent: comparesKEEPALIVE_VERSIONheaders, only writes on change. Refuses to overwrite a foreign mu-plugin (defensive against name collisions). Failure is non-fatal — install errors are recorded inwp_optionsfor wpdeploy visibility but never throw.
Net effect. Any site that successfully loads AF 3.7.0.4 or later will have the keepalive permanently installed in mu-plugins. From that point forward, even if a future update hard-fails, the keepalive recovers AF on the next pageview without any manual intervention or filesystem access. Crucially: this works on sites we don't own — the keepalive ships inside the AF zip, gets installed during the first successful update, and lives in mu-plugins thereafter.
2. Forensic markers
The keepalive writes three options on each recovery:
auctionforge_auto_reactivated_at— most recent recovery timestampauctionforge_auto_reactivated_count— total recoveriesauctionforge_auto_reactivated_failed_at— set when the keepalive saw AF on disk but with no Plugin Name header (genuinely corrupt — needs operator attention)
These get picked up by the AF sync streams and surfaced on the wpdeploy dashboard so you can see which sites have been quietly recovering themselves and whether a particular release is failing more than it should.
3. Companion: post-update-silence alerts on wpdeploy (server side)
Wpdeploy's
report-healthroute now compares incomingplugin_versionagainst the row and writeslast_version_changed_at+previous_plugin_versionon change. TheSyncWatchdogcron then alerts if a site has reported a version change but not sent any heartbeat for 2+ hours since — likely a failed install. Emitssync_incidentsrows withkind=post_update_failureso the existing Telegram fan-out picks them up. Each version-change event alerts at most once.Files Changed
- Created:
inc/keepalive/auctionforge-keepalive.template.php,inc/keepalive/class-keepalive-installer.php - Modified:
inc/stats/class-stats-init.php(callAF_Keepalive_Installer::maybe_install()on every plugin load) - Modified:
auctionforge.php(Version 3.7.0.3 → 3.7.0.4)
Companion server-side changes (already deployed on wpdeploy.smoothbyteit.dev — not in this zip):
sitestable:last_version_changed_at TIMESTAMP NULL,previous_plugin_version VARCHAR(20) NULLapi.php/report-health route detects version changesSyncWatchdog::maybe_alert_post_update_failure()emits the new alert kind
Verification
1. Drop a 3.7.0.4 install on any site. Confirm
wp-content/mu-plugins/auctionforge-keepalive.phpexists post-load.2. Manually deactivate AF from the database (
DELETE FROM wp_options ...active_plugins...). Hit the homepage. AF reappears inactive_plugins;auctionforge_auto_reactivated_countincrements.3. Delete
mu-plugins/auctionforge-keepalive.php. Trigger AF load (any pageview). The file reappears.4. Bump KEEPALIVE_VERSION in the source template, ship a new release, observe the installed mu-plugin update on next AF load.
Operator notes
- Sites currently in the broken state (AF deactivated, no keepalive yet) are NOT auto-rescued by this release — they need a one-time manual reactivation in wp-admin OR a fresh AF install via wp-admin's Upload Plugin. After that, the keepalive is in place and future failures self-heal.
- The post-update-failure alert won't fire for upgrades that happened before this release (no
last_version_changed_atwas recorded). It activates from the first version change wpdeploy sees from each site after this update lands.
---
[3.7.0.3] — 2026-05-02
Fix: profile re-sync on login / profile-edit / register (no more empty names)
Why
The hourly profile sync uses a
user_registeredwatermark — once a user has been pushed once, the watermark advances past them and they're never re-pulled. That meant:1. Existing users whose first_name/last_name became populated AFTER their first sync stayed empty on wpdeploy forever.
2. BidSpirit-driven sites that don't write WP's standard
first_name/last_namefields shipped empty rows even though the canonical name was visible indisplay_name.The People view was showing
—for the name on rows that absolutely had a name available — just not where the sync handler was looking.Fixes (
inc/sync/class-profile-sync.php+inc/stats/class-stats-init.php)AF_Profile_Sync::push_for_user_id($user_id, $blocking=false)— new public method that builds a single user's profile row, normalises it, and POSTs to wpdeploy bypassing the watermark. Non-blocking by default (wp_remote_postwithblocking=false, timeout=2s) so login latency is unaffected.build_user_row($user_id)extracted as a reusable helper. Both the hourly batch and the on-demand push call it. Centralises role-filtering + display_name fallback + usermeta probing.display_namefallback. Whenwp_usermeta.first_name/last_nameare both empty (typical on BidSpirit-only sites),build_user_row()parsesdisplay_name("John Smith" → first=John, last=Smith) so we don't ship a row with a blank name when the data is sitting on the user record itself.- Three new action hooks registered in
class-stats-init.php::init(): wp_login→push_for_user_id($user->ID)— every login refreshes the rowprofile_update→ same — profile edits in wp-admin refreshuser_register→ same — new registrations get pushed instantly (instead of waiting up to 60 min for the next cron tick)
Files Changed
- Modified:
inc/sync/class-profile-sync.php(refactor + new method + display_name fallback) - Modified:
inc/stats/class-stats-init.php(three new action hooks) - Modified:
auctionforge.php(Version 3.7.0.2 → 3.7.0.3)
Verification
1. On a 3.7.0.3 site, find a user whose
wpdeploy.user_profiles.first_nameis empty:SELECT site_id, email, first_name FROM user_profiles WHERE email='something@example.com'2. Log in as that user (or have them log in).
3. Within ~2 seconds, re-query —
first_nameshould now be populated, either from the standard meta key OR parsed fromdisplay_name.4. The non-blocking POST means the user's login experience is unchanged — no spinner, no extra latency.
Operator note
Existing wpdeploy rows with empty
first_name/last_namewill refresh automatically as users log in or edit their profile. To force a one-shot re-walk of every user on a site (regardless of watermark), reset the watermark there:DELETE FROM wp_options WHERE option_name='auctionforge_profile_sync_watermark';Next hourly cron will re-pull every non-admin user with the new fallback applied.
---
[3.7.0.2] — 2026-05-02
Fix: sync-lots datetime mismatch + idle syncs now heartbeat
Why
Two issues surfaced in the wpdeploy Sync Health dashboard:
1. Every site's
sync-lotswas stuck onapi_error. The plugin sendslast_modifiedstraight fromwp_bp_meta_data.lastUpdate, which is a Unix epoch string ("1756919754"). wpdeploy'slots.last_modifiedcolumn is aDATETIME, so MariaDB rejects the insert withSQLSTATE[22007]: Incorrect datetime value. The handler recordsapi_errorand the watermark never advances, so every cron tick re-fails on the same batch.2. Sites with nothing to sync looked dead. When a sync handler had an empty batch (e.g. no non-admin users yet) it was returning early without POSTing anything. wpdeploy's
update_sync_health()only fires on a successful POST, sosites.sync_health_jsonstayed NULL and the dashboard showed grey dots — indistinguishable from a broken cron. WP-Cron was actually firing fine; the watchdog just couldn't tell.Fixes
inc/sync/class-lots-sync.php— newepoch_to_datetime()helper converts the BidSpirit epoch field to UTCY-m-d H:i:sbefore shipping. Idempotent: already-formatted datetimes pass through untouched, invalid values becomeNULL.inc/sync/class-sync-base.php::run()— always POST, even when the batch is empty. Empty payload is{records: []}and wpdeploy's existing handlers handle it gracefully (loop is skipped,update_sync_health()still fires withsynced=0). This makes the dashboard reflect cron liveness, not just data flow.
Files Changed
- Modified:
inc/sync/class-lots-sync.php - Modified:
inc/sync/class-sync-base.php - Modified:
auctionforge.php(Version 3.7.0.1 → 3.7.0.2)
Verification
1. On Clumber:
do_action('auctionforge_sync_lots')— confirm the previousauctionforge_last_sync-lots_status = api_errorflips tosuccess(N)and thatwpdeploy.lotsnow contains rows.2. On a site with no non-admin users:
do_action('auctionforge_sync_user_profile')— confirmauctionforge_last_sync-user-profile_status = idle(0)AND that wpdeploy's Sync Health page now shows a green dot for that cell.---
[3.7.0.1] — 2026-05-02
Fix: marketing data leaks WordPress admins into the people list
Why
After the 3.7.0.0 rollout the central
peopleview on wpdeploy was showing site administrators alongside real auction-house users — thesync-user-profilehandler read straight fromwp_userswith no role filter, so any account with administrator/editor/author/contributor/shop_manager capabilities was getting shipped as if it were a buyer. Marketing audiences must contain buyers, not staff.Fixes (
inc/sync/class-profile-sync.php)- The
read_batch()SQL now LEFT JOINs{$wpdb->usermeta}on the prefix-aware capabilities key ({$wpdb->prefix}capabilities) and filters out any user whose serialized capabilities meta_value containsadministrator,editor,author,contributor,shop_manager, orsuper_admin. Users withIS NULL(no roles registered) are still allowed through — those are typically subscribers/buyers on this fleet. - Watermark on
auctionforge_profile_sync_watermarkis unchanged; the next run after upgrade picks up the same batch with the new filter applied. Operationally the wpdeploy team also wiped the existing admin rows fromuser_profiles,user_interests,user_recent_activity,bids_wins, andpeopleto clear the leak server-side — total of 35 rows scrubbed.
Files Changed
- Modified:
inc/sync/class-profile-sync.php - Modified:
auctionforge.php(Version 3.7.0.0 → 3.7.0.1)
Verification on Clumber dev
1. Find a logged-in admin:
SELECT u.user_email FROM wp_users u JOIN wp_usermeta um ON um.user_id=u.ID AND um.meta_key='wp_capabilities' WHERE um.meta_value LIKE '%administrator%';2. Reset the watermark:
DELETE FROM wp_options WHERE option_name='auctionforge_profile_sync_watermark';3. Trigger sync:
do_action('auctionforge_sync_user_profile');4. On wpdeploy: confirm those admin emails do NOT appear in
user_profiles(SELECT * FROM user_profiles WHERE email='admin@…';returns zero rows).Privacy / scope
- No API contract changes. The wpdeploy
/api.php/sync-user-profileroute accepts the same payload shape; this is purely a source-side filter narrowing what gets sent.
---
[3.7.0.0] — 2026-05-02
Cross-site user data lake — full Phase 2 + Phase 3 build
Why
AuctionForge sites were exposing per-lot engagement (views, favourites, bids, wins) keyed only on the anonymous
af_vidlocalStorage hash, with no central aggregation. Marketing — even the "collect data now, send later" phase — needs a per-person view across the whole AF network: name + phone + postcode + country + IP + device fingerprint + the keywords they engage with + the bids they place + the lots they win, all rolled up across every site they've used. This release wires every piece needed for that, and keeps it sustainable: per-site aggregates rather than raw event firehose, watermarked syncs with retry, 14/30-day site-side retention, watchdog + Telegram alerts for dead streams.See
/root/.claude/plans/i-want-to-add-synthetic-goose.mdfor the full architecture.New tables (idempotent dbDelta on the existing
plugins_loadedmigration path)wp_af_stats_lot_keywords— per-lot keyword cache. Title + tags + author tokenized (lowercase → drop stop-words → drop ≤2-char → drop pure-digit), one row per (post_id, keyword). Populated onsave_post_lot.wp_af_user_interests— running tally per(user_email, dimension, dimension_value)where dimension ∈keyword | category | author | price_band. UPSERT-keyed so increments are atomic. Bounded by users × distinct interests (typically a few dozen rows per user).wp_af_user_recent_activity— capped per-user activity log (last 50 events per email). Seeds the drill-down timeline on the wpdeploy person view.wp_af_bid_events— bid + win events (auto-created by the bids sync handler). Drained and shipped to wpdeploy hourly.synced_atcolumns added towp_af_stats_pageviews,wp_af_stats_sessions,wp_af_stats_searches,wp_af_stats_outbound. Powers the durable sync-and-purge lifecycle.af_stats_db_versionbumped 2 → 3. The existingAF_Stats_Init::maybe_create_tables()picks up the new tables on the next admin page load after auto-update.
New helper classes
AF_Keyword_Extractor(inc/stats/class-keyword-extractor.php) — pure tokenizer + cache writer + read-through helper. Hookssave_post_lotto refresh on lot changes. Stop-words tunable viaapply_filters('af_keyword_stop_words', ...).AF_User_Interests(inc/stats/class-user-interests.php) —record_view / record_favorite / record_bid / record_win. All idempotent UPSERTs. CallsAF_Stats_Tracker::should_skip()first so admins/bots never pollute interest profiles.AF_Sync_Base(inc/sync/class-sync-base.php) — abstract durability backbone. Readssynced_at IS NULLbatches, POSTs, marks rows synced only on a confirmed 200, retries on next cron run if the POST fails. Idempotent UNIQUE keys on the wpdeploy side mean retries never duplicate.AF_Profile_Sync/AF_Interests_Sync/AF_Activity_Sync/AF_Lots_Sync/AF_Bids_Sync— five concrete sync streams.AF_Data_Purge(inc/maintenance/class-data-purge.php) — daily cron: 14-day floor on synced rows, 30-day hard cap with CRITICAL alert if any unsynced row hits the cap (which would mean wpdeploy has been unreachable for a month).
New cron schedules (auto-registered on plugins_loaded if
auctionforge_update_server_url+_api_keyare configured)| Hook | Schedule | Endpoint |
|---|---|---|
|
auctionforge_sync_user_profile| hourly |POST /api.php/sync-user-profile||
auctionforge_sync_user_interests| hourly |POST /api.php/sync-user-interests||
auctionforge_sync_user_activity| hourly |POST /api.php/sync-user-activity||
auctionforge_sync_lots| every 10 min |POST /api.php/sync-lots||
auctionforge_sync_bids_wins| hourly |POST /api.php/sync-bids-wins||
auctionforge_purge_synced_data| daily | (purge cron — local) |All sync handlers are watermarked or
synced_at-gated; cron mid-run failure is harmless because the next run picks up the same rows.Hooks fired
af_stats_pageview_recorded($url, $email, $visitor_hash)— fires insideAF_Stats_Ajax::handle_track()after a logged-in pageview is recorded. Default listener resolves URL → lot post →AF_User_Interests::record_view().af_stats_lot_favorited($email, $post_id)— fires from the existinglot_analytics_record_favoriteAJAX handler when a watchlist add happens. Default listener callsrecord_favorite().
Server-side companion (wpdeploy)
This release is paired with wpdeploy changes (handled out-of-band; not in the plugin zip):
- 5 new API routes matching the sync streams above. All return
synced+ watermark metadata so the plugin can advance / mark rows synced. update_sync_health()helper in wpdeploy — every successful sync POST writes(stream, last_seen_at, last_synced_count, state)intosites.sync_health_json.SyncWatchdog— 5-minute cron on wpdeploy that scans every (site × stream) cell and runs anok → overdue → gone → recovering → okstate machine. Emits alerts via the existingsync_incidentsTelegram fan-out.- People section in the wpdeploy admin —
?tab=people(cross-site rollup with top keywords / lifetime spend),?tab=person&email=...(drill-down with timeline + bids),?tab=people-export(Google Customer Match + Meta Custom Audience CSV with sha256 hashing per spec). ?tab=sync-health— site × stream traffic-light grid showing every sync's state.
Files Changed
- Created:
inc/stats/class-keyword-extractor.php,inc/stats/class-user-interests.php,inc/stats/stop-words.php - Created:
inc/sync/class-sync-base.php,inc/sync/class-profile-sync.php,inc/sync/class-interests-sync.php,inc/sync/class-activity-sync.php,inc/sync/class-lots-sync.php,inc/sync/class-bids-sync.php - Created:
inc/maintenance/class-data-purge.php - Modified:
inc/stats/class-stats-database.php(DB_VERSION = 3, new dbDelta calls, synced_at column adds) - Modified:
inc/stats/class-stats-init.php(require new classes, register sync crons, wireaf_stats_pageview_recordedandaf_stats_lot_favoritedlisteners) - Modified:
inc/stats/class-stats-ajax.php(fireaf_stats_pageview_recordedafter pageview record; fireaf_stats_lot_favoritedon watchlist add) - Modified:
auctionforge.php(Version: 3.6.4.0 → 3.7.0.0)
Verification on Clumber dev
1. After auto-update + first wp-admin page load:
wp_af_stats_lot_keywords,wp_af_user_interests,wp_af_user_recent_activityall exist;af_stats_db_version = 3.2. Save a test lot titled
"Pair of Victorian silver candlesticks by Mappin & Webb"→wp_af_stats_lot_keywordshas rows forvictorian, silver, candlesticks, mappin, webb(and notpair, of, by).3. Log in as throwaway test user, view 3 of those lots →
wp_af_user_interestsshows(test@…, keyword, 'victorian', view_count=3).4. Wait one hourly cron, confirm
wpdeploy.user_interestsmirror via the wpdeploy admin →?tab=people→ search for the test email.5. Confirm
wpdeploy.sites.sync_health_jsonhasuser-interests.state = 'ok'for the Clumber site.6. Pause the cron, wait 2h, watch the watchdog flip the cell to
overdueand emit a Telegram alert.Privacy / scope
- Admins and bots are filtered out at write time via
AF_Stats_Tracker::should_skip(). - Email is normalized lowercase + trim before storage; phone normalized to E.164 (UK-aware) on the sync side.
- No outbound activation yet — wpdeploy stores everything but doesn't send anything to anyone. Marketing send mechanics (consent flag, suppression list, sender) explicitly deferred.
---
[3.6.4.0] — 2026-05-02
Identity stitching: visitor_hash → user_email
Why
The
af_stats_*tables (pageviews,sessions,searches,outbound) and the lot-engagement tables (af_lot_analytics,af_lot_shares) currently store activity keyed only on the anonymousaf_vidlocalStorage hash — there is no link from any browsing event to the user's email even when they're logged in. Without that link, the central wpdeploy server can never aggregate behavioural data on a per-person basis, which is the prerequisite for the cross-site user-data lake being built on wpdeploy (see/root/.claude/plans/i-want-to-add-synthetic-goose.mdPhase 1).This release adds the bridge: every authenticated tracker hit records a
(visitor_hash, user_email)pair into a new table. From here on, anonymous browsing can be resolved to an email via JOIN for any session the user was logged in.Changes
- New table
wp_af_stats_visitor_emails—(visitor_hash, user_email, ip_address, first_seen, last_seen)withUNIQUE(visitor_hash, user_email)+ index onuser_email. Created viadbDeltainside the existingAF_Stats_Database::create_tables()so it ships through the standardplugins_loadedmigration path — no manual reactivation needed after auto-update. af_stats_db_versionbumped 1 → 2.AF_Stats_Init::maybe_create_tables()now compares against the newAF_Stats_Database::DB_VERSIONconstant rather than a hard-coded< 1, so future schema bumps (Phase 2 onwards) just require constant edits + new dbDelta calls.- Identity record on every authenticated tracker hit.
AF_Stats_Ajax::handle_track()now callsAF_Stats_Visitor_Email_Map::record($visitor_hash, $email, $ip)wheneveris_user_logged_in()is true. Trust boundary: the email is read server-side fromwp_get_current_user()— clients cannot assert who they are. - Defensive table-exists guard. The new helper short-circuits silently if the migration hasn't run yet on a given site (race window on the very first request after auto-update); the next request finds the table and proceeds. No fatals, no missing rows.
- Email normalised at write time — lowercase + trim +
is_email()validation before storage. Marketing audience match-rates downstream depend on consistent casing.
Files Changed
- Created:
inc/stats/class-visitor-email-map.php - Modified:
inc/stats/class-stats-database.php(DB_VERSION constant; new table; drop_tables list) - Modified:
inc/stats/class-stats-init.php(require new helper; migration check uses constant) - Modified:
inc/stats/class-stats-ajax.php(record pair inhandle_track) - Modified:
auctionforge.php(Version header bump)
Verification on Clumber dev
1. After auto-update, load any
wp-admin/*page once →wp_af_stats_visitor_emailsexists,af_stats_db_version = 2.2. Log in as a test user, browse 5 lots → exactly one row in
wp_af_stats_visitor_emailsfor that(visitor_hash, email)pair, withlast_seenupdating on each hit.3.
SELECT email FROM wp_af_stats_visitor_emails WHERE visitor_hash IN (SELECT visitor_hash FROM wp_af_stats_pageviews WHERE created_at > NOW() - INTERVAL 1 HOUR)returns the test email — proving the JOIN works.Privacy / scope
- This change writes a
(visitor_hash, email)pair to a single new table on the AF site. Nothing is sent to wpdeploy yet — the sync stream lands in Phase 2. - Anonymous (logged-out) browsing is unaffected: no row is created until the user authenticates.
- Bots are still skipped via
AF_Stats_Tracker::is_bot()before any tracking writes.
---
[3.6.3.1] — 2026-05-01
Fix: New lots never processed + Live console improvements
Why
When BidSpirit adds new lots to an auction (e.g. items 683-692), the sync pipeline correctly staged all 709 lots into
import_historybut the InsertLotsBS processing loop exited after the first batch of 500 unchanged lots, never reaching the genuinely new lots at the tail of the queue. This caused new lots to remain permanently stuck in staging — synced but never created as WordPress posts.Separately, the admin Live Console was replaying the entire log history from the beginning on every page load, and showed long silent gaps during API calls with no indication of what the worker was doing.
Fixes
- InsertLotsBS loop break condition — The stage 5 insert loop in
CatalogSyncWorker::process()andprocessDayEnded()previously broke whenupdated lots === 0, even if the batch had cleared hundreds of unchanged ("unupdated") lots from the queue. New lots with higher IDs were never reached. Now breaks only when bothupdated lotsandunupdated lotsare 0, meaning the staging queue is truly empty. - Live Console starts from current position —
consoleSinceIdwas hardcoded to0, causing the console to page through the entireaf_sync_logtable (50 rows at a time) before reaching real-time entries. Now initializes toSyncLogger::getLatestId()so only entries created after page load appear. queueIsActivedeclaration order — Variable was declared after functions that referenced it, causing the console to always start at the slow 3s polling rate even when a worker was active. Moved declaration before first use.- Progress logging during API calls —
LotList::auctionProcessing()made 2-3 BidSpirit API calls with zeroSyncLoggerentries, creating long silent gaps in the console. Added log entries for API fetch start, response received (with duration), data staged, and API errors. - Per-auction progress in bulk runs —
LotList::run()now logsProcessing auction X/Y: {id}for each auction in the bulk loop, and logs skipped auctions. processDayEndedinsert loop logging — Added batch progress logging and timeout guard matching theprocess()method pattern. Previously this loop was completely silent.
Files Changed
- Modified:
inc/sync/CatalogSyncWorker.php,inc/import/LotList.php,admin/view/sync-status.php
---
[3.6.3.0] — 2026-05-01
Public Auctions API — Token Authentication
Why
The
/wp-json/auctionforge/v1/public/auctionsendpoint added in v3.6.2.9 was publicly accessible. Since auction data should only be served to authorized aggregator sites, the endpoint now requires a valid auth token.Changes
- Token verification — The
PublicAuctionsREST endpoint now validates anX-AF-Tokenheader (or?token=query parameter) against the site's existing Webhook auth token from AuctionForge settings. - Returns
401 Unauthorizedfor missing/invalid tokens and403 Forbiddenif no auth token is configured on the site. - Uses
hash_equals()for timing-safe comparison.
Files Changed
- Modified:
auctionforge.php,inc/api/PublicAuctions.php
---
[3.6.2.9] — 2026-05-01
Public Auctions REST API Endpoint
Features
- New REST endpoint
GET /wp-json/auctionforge/v1/public/auctions— Exposes auction list data (title, date, image, state, catalog link) for consumption by the AuctionForge Hub plugin on parent/main sites. - Parameters:
type(upcoming or past, default: upcoming),limit(max results, default: 50). - Handles multi-day auctions with correct part numbers and catalog links.
- Returns auction metadata including
auction_id,source_site, andday_indexfor deduplication.
Files Changed
- Modified:
auctionforge.php,inc/coreIncludes.php - Created:
inc/api/PublicAuctions.php
---
[3.6.2.8] — 2026-04-30
Suppress alerts for transient retry conditions
Why
The "BidSpirit API returned 0 lots — catalog may not be ready yet" message is logged when the BidSpirit webhook fires before the auction catalog is fully published. The safety cron retries the job automatically and it usually succeeds on the next attempt — there's no operator action required, so a Telegram alert is just noise.
Fix
- New private helper
SyncLogger::isSuppressedFromAlerts($message, $context)matches the message against a substring allowlist of known-transient errors. When matched, the row is still inserted intoaf_sync_log(so the in-app sync console still shows the retry chain) but theauctionforge_sync_error_loggedfan-out action does NOT fire — wpdeploy and Telegram stay quiet. - Default suppression substrings:
"BidSpirit API returned 0 lots","catalog may not be ready yet". - Extendable via the new
auctionforge_sync_alert_suppress_patternsfilter — themes/MU plugins can add their own substrings.
Files Changed
- Modified:
auctionforge.php,inc/sync/SyncLogger.php
---
[3.6.2.7] — 2026-04-30
Typo fix
- Settings → Connections tab: the placeholder/help text under the Server field showed
https://my-accaunt.bidspirit.com/(extra "a"). Now readshttps://my-account.bidspirit.com/.
Files Changed
- Modified:
auctionforge.php,inc/controllers/Settings.php
---
[3.6.2.6] — 2026-04-30
Fix stale
plugin_versionin reportsWhy
Sites were reporting their old version to wpdeploy long after they'd been upgraded — e.g. Lonsdale Auctioneers ran v3.6.1.1 but kept telling wpdeploy it was on v2.9.6. Root cause: the constant
AUCTIONFORGE_VERSIONis read from the plugin file'sVersion:header *once at plugin load*, then frozen into$this->current_versionon the auto-updater instance. After a plugin upgrade replaces the file on disk, existing PHP-FPM workers keep using the cached constant value until they're recycled, so every report from those workers carries the old version.Fix
- New helper
AuctionForge_Auto_Updater::get_live_version()reads the version directly from the plugin file's header on each call (viaget_file_data()— uncached). report_health,push_sync_error_immediate, andretry_sync_errorsnow sendget_live_version()instead of the cached constant.- The pre-existing iteration through active plugins inside
report_healthalready usedget_plugin_data()per plugin, so secondary plugin entries were already accurate; only the top-levelplugin_versionfield was stale.
Files Changed
- Modified:
auctionforge.php,inc/class-auto-updater.php
---
[3.6.2.5] — 2026-04-30
Real diagnostics for plugin self-updates
Why
The wpdeploy
update_queuetable had a 46% historical failure rate, but every single failure row stored the literal string"Installation failed"— collapsing every failure mode into one opaque error with no diagnostic value. Root cause: theinstall_update()method in both clients (AF auto-updater and wpd-client) treatedPlugin_Upgrader::upgrade()as a boolean, throwing awayWP_Errorobjects and skin-emitted error messages.Fixes (
inc/class-auto-updater.phpinstall_update())- Refreshes the
update_pluginstransient before invoking the upgrader. The upgrader reads from this transient to know what version to download; if WP hasn't checked recently, the upgrader silently returns false (looking like a failure even though there's a real update queued at wpdeploy). - Distinguishes
WP_Error,false/null, and success.WP_Errorwas previously treated as truthy → reported as "completed" even on failure. Now extracts the error code and message. - Reads
Automatic_Upgrader_Skin::get_errors()to surface the real upgrader-emitted error messages. - Reads
$upgrader->resultwhich holds the finalWP_Errorfor some failure paths. - Captures PHP errors/warnings emitted during the upgrade (file-move issues, etc.) via a temporary
set_error_handler. - Detects "no update in transient" as a distinct failure cause and labels it explicitly so we know it's a transient-cache problem, not an actual install failure.
- Truncates the combined diagnostic to 1000 chars before sending.
The same fix is applied to
wpd-client.php(the WPD client plugin shipped fromclient-plugin/wpd-client.phpon the wpdeploy server).Files Changed
- Modified:
auctionforge.php,inc/class-auto-updater.php
---
[3.6.2.4] — 2026-04-30
Bulk-sync worker dispatch fix
Fixes
- The HTTP-loopback worker (
auctionforge_rest_sync_workerinauctionforge.php) had its own switch statement for job-type dispatch, distinct from the one incrontasks/syncWorker.php. The newfull_sync_upcomingandfull_sync_pastjob types were only added to the CLI worker, so the loopback path produced "Unknown job type" errors. Both switches now route those types toBulkSyncWorker::process. inc/coreIncludes.phpnowrequire_oncesBulkSyncWorker.phpso the class is available wherever sync code runs.
Files Changed
- Modified:
auctionforge.php,inc/coreIncludes.php
---
[3.6.2.3] — 2026-04-30
Fixes for end-to-end Telegram round-trip
Fixes
verify_api_keyreads the option fresh on every call (hash_equalsagainstget_option('auctionforge_update_api_key')) instead of relying on the cached$this->api_keyfrom constructor time. Different FPM workers can hold different cached values when the option drifts (e.g. via auto-heal collisions), which previously produced intermittent 401s on REST endpoints.- New REST endpoint
POST /wp-json/auctionforge/v1/sync/version— wraps the existingtrigger-installflow with a JSON response (always HTTP 200 withsuccessflag). The original endpoint returnedWP_Error('no_update', …, status: 404)when the plugin was already on the latest version, which nginx'serror_page 404directive then clobbered with a static HTML 404 page on hosts using aaPanel/BTWAF. Keeping the URL under/sync/*matches the pattern that's already proven to pass through host WAFs.
Files Changed
- Modified:
auctionforge.php,inc/class-auto-updater.php
---
[3.6.2.2] — 2026-04-29
Catalog-sync kind disambiguation
Fix
catalog_syncjobs target a single auction that may be either active or archived. Until now their alerts were always classified askind=upcoming. The classifier now resolves the auction'sauction_stateterm meta and routes:ARCHIVED/ENDED/POST_AUCTION→kind=past→ Kill + Full Past buttons- anything else (or unresolvable) →
kind=upcoming→ Kill + Full Upcoming buttons
Files Changed
- Modified:
auctionforge.php,inc/class-auto-updater.php
---
[3.6.2.1] — 2026-04-29
Telegram Sync Monitoring follow-ups
Features
- Context-aware alert buttons. Each Telegram alert now shows the action set most relevant to the failing sync: upcoming-sync errors get Kill + Full Upcoming, past-sync errors get Kill + Full Past, everything else gets Kill only. Button choice is driven by a new
kindfield classified at log-write time from the queue'sjob_type. - Plugin version in alerts + Update button. Each push now includes the live
plugin_version. wpdeploy compares it to the latestis_stable=1row in itsversionstable and only renders an Update plugin button when the site is behind. Tapping Update calls the existingPOST /wp-json/auctionforge/v1/trigger-installendpoint to force the upgrade.
Architecture
- New private helper
AuctionForge_Auto_Updater::classify_error_kind($jobId)looks up the job'sjob_typeand maps it to'upcoming'/'past'/'other'. Used by both the immediate push and the 1-min retry cron. - Outbound payloads now include
plugin_versionat the top level; wpdeploy refreshessites.plugin_versionon every/sync-errorsPOST.
Files Changed
- Modified:
auctionforge.php,inc/class-auto-updater.php
---
[3.6.2.0] — 2026-04-29
Telegram Sync Monitoring & Remote Control
Features
- Instant Telegram alerts on sync errors. Any
level='error'row written toaf_sync_logis pushed (fire-and-forget, non-blocking) to wpdeploy, which fans it out to a configured Telegram group with inline-keyboard action buttons (Kill / Full Upcoming / Full Past / Acknowledge). - Remote command surface. Any group admin can tap a button to:
- Kill sync — flips DB flags via
SyncQueue::cancelAll(), then SIGTERMs every active worker; a 5-second watchdog escalates to SIGKILL for any survivor. - Full sync upcoming — full re-import of every active auction and its lots (queued, observable, killable). Replaces the
re-sync?do=importBidSpiritUpcomingflow with a queued equivalent. - Full sync past — same, for archived auctions.
- Safety-net retry cron (
auctionforge_retry_sync_errors, every minute) re-pushes recent error rows. wpdeploy dedupes viaUNIQUE(site_id, af_log_id)so duplicates are silent.
Architecture
SyncLogger::log()now firesdo_action('auctionforge_sync_error_logged', …)onlevel='error'so any handler can react. The auto-updater listener does a 2 s non-blocking POST to/api.php/sync-errors.- New REST endpoint
POST /wp-json/auctionforge/v1/sync/cancel-all(X-API-Key auth) — runsSyncQueue::cancelAll()+ SIGTERM + watchdog. Logs every action throughSyncLogger. POST /sync/startextended with amodeparameter (upcomingdefault,pastfor archived). Bulk re-sync is now a queued job, not a synchronous block.- New job types
full_sync_upcomingandfull_sync_pastonSyncQueue, dispatched to a newBulkSyncWorkerthat wraps the existingAuctionList::init()+LotList::init($upcoming)pipeline. syncWorker.phpinstalls a SIGTERM handler that flips the in-flight job tofailedwith a "Killed by admin (SIGTERM, cleanup OK)" marker and closes the DB cleanly before exiting. Watchdog escalates to SIGKILL after 5 s grace.LotList::auctionProcessing()now heartbeats the active bulk-sync job between auctions, preventing the safety cron from auto-failing long bulk runs as stale (the 600 s threshold is unchanged).
Files Changed
- Modified:
auctionforge.php,inc/sync/SyncLogger.php,inc/sync/SyncQueue.php,inc/class-auto-updater.php,crontasks/syncWorker.php,inc/import/LotList.php - Created:
inc/sync/BulkSyncWorker.php
---
[3.6.1.6] — 2026-04-29
High-Value Lot Modes for
[bp_lot_list]Features
high_value_pastmode — Displays past auction lots ordered by their catalog estimate (estimatedPriceInt), highest first. Useful for "Top Lots" or "Highlights" sections.high_value_soldmode — Displays past sold lots ordered by their actual sold price (soldBid), highest first. Only includes genuinely sold lots (soldBid > 0) and reuses the same false-positive guard asrandom_pastto skip lots wheresoldBidwas carried over fromstartPricewithout real bidding activity.- Admin documentation updated — The Shortcodes reference page in WP Admin now lists both new modes in the
modeattribute description and includes example shortcode usage.
Architecture
- New constants
MODE_HIGH_VALUE_PASTandMODE_HIGH_VALUE_SOLDonLotsWidget. - New method
LotsWidget::getLotListHighValue($mode, $limit)builds the query, applies the past-auction tax filter, setsbp_orderbyto the relevant meta field withDESCorder, and (for the sold variant) filters out unsold-but-stale lots in PHP. - New filter hook
bp_lot_list_high_value_args_filterfor downstream customization of the WP_Query args.
Files Changed
- Modified:
inc/widgets/LotsWidget.php,inc/controllers/ShortcodesPage.php
---
[3.6.0.18] — 2026-04-25
Brevo SMS Notifications Integration
Features
- Transactional SMS via Brevo API — The plugin now sends text message alerts through the Brevo transactional SMS service, running alongside existing Firebase push notifications.
- Four Notification Types:
- New Auction Published — Broadcast SMS to all opted-in subscribers when an auction is published.
- Auction Starting Soon — Targeted SMS to users registered for an auction when it is about to start.
- Favorited Item Live Soon — Targeted SMS to users who favorited a lot when it is approaching in the auction.
- Outbid Notice — SMS sent when a user's leading bid is surpassed, with a 5-minute per-item cooldown to prevent spam.
- SMS Subscriber Database — New
af_sms_subscriberstable stores user phone numbers, country codes, and per-notification-type opt-in preferences (GDPR-ready explicit consent). - Admin Settings Tab — New "SMS Notifications" tab in Settings with:
- Brevo API Key input
- SMS Sender Name (11 char max)
- Master enable/disable toggle
- Per-notification-type on/off switches
- Test SMS widget with phone input and send button
- Live subscriber count display
- Profile SMS Preferences — Users can opt into SMS notifications directly from their profile page with phone number entry and granular notification type selection.
Architecture
- BrevoSMS Service (
inc/services/BrevoSMS.php) — cURL-based API wrapper with broadcast, targeted, and single-send methods, message builders with 160-char limit awareness, rate limiting, and comprehensive error logging. - SMSSubscriber Model (
inc/model/SMSSubscriber.php) — CRUD operations, email-to-phone resolution, opt-in filtering, and upsert logic. - Webhook Integration — SMS dispatch hooks added to
AuctionsAPI.phpmethods:leading_bid_surpassed(),item_live_soon(),auction_starts_soon(), andauctionPublishedPush().
AJAX Handlers
auctionforge_sms_save— Save SMS preferences from profile pageauctionforge_sms_load— Load SMS preferences for profile pageauctionforge_sms_test— Admin-only test SMS endpoint
Database
- New table:
af_sms_subscribers— Phone numbers, country codes, per-notification opt-ins, timestamps
Files Changed
- Modified:
auctionforge.php,inc/coreIncludes.php,inc/controllers/AuctionsAPI.php,inc/controllers/Settings.php,admin/view/settings.php,templates/parts/profile-templates.php - Created:
inc/services/BrevoSMS.php,inc/model/SMSSubscriber.php
---
[3.6.0.7] — 2026-04-14
Hotfix
Fixes
- Namespace resolution — Fixed fatal error in
wp_footercommission label hook caused by unqualifiedSettingsHelperandSettingsclass references. Now uses fully qualified namespaces.
Files Changed
- Modified:
auctionforge.php
---
[3.6.0.6] — 2026-04-14
Commission Label Override Fix
Fixes
- Theme template override compatibility — Moved the commission label JS override from the
single-lot.phptemplate intoauctionforge.phpviawp_footerhook (priority 99). Sites with theme-level template overrides (e.g.themes/*/auctionforge/single-lot.php) were not picking up the inline script. Thewp_footerapproach works universally on all single lot pages.
Files Changed
- Modified:
auctionforge.php,templates/single-lot.php
---
[3.6.0.5] — 2026-04-14
Commission Label Override
Features
- Commission Label Setting — New dropdown in Settings → Appearance allowing admins to choose between "Buyer's Premium" (default) and "Auction House Commission" as the label displayed on lot pages. This overrides the Bidspirit JS client's default label using a MutationObserver that catches asynchronously injected text.
Files Changed
- Modified:
inc/controllers/Settings.php,templates/single-lot.php
---
[3.6.0.4] — 2026-04-12
Auction Approval Modal Redesign
Changes
- Removed BidSpirit Terms of Use — The generic BidSpirit "Terms of Use" section that appeared at the top of the non-credit-card approval modal has been removed. The modal now shows only the auction house's own legal agreements managed within the plugin.
- Renamed Modal Title — Changed "Terms of conditions" to "Terms & Conditions".
- Larger Scroll Area — The Terms & Conditions scroll box is now 350px tall (up from 200px) for easier reading.
- Proportional Section Heights — Refund & Return Policy and Chargeback Waiver sections use a shorter 260px scroll box to visually distinguish them from the primary Terms & Conditions.
Files Changed
- Modified:
templates/js-chunks/approval-info.php,assets/js/app.js
---
[3.6.0.2] — 2026-04-10
Webhook Token Generator
Features
- Token Generator Widget — Added a 16-character random token generator directly below the "Webhook auth token" field on the Settings page. Includes a "Generate Token" button and a clipboard copy icon with visual feedback.
Files Changed
- Modified:
inc/controllers/Settings.php
---
[3.6.0.1] — 2026-04-10
Patch
Changes
- Version bump.
---
[3.6.0.0] — 2026-04-10
Legal Agreements for Auction Approval
Features
- Terms & Conditions — A mandatory, scrollable Terms & Conditions document is now displayed during the auction approval process. Bidders must scroll to the bottom and check an agreement box before their approval request is submitted. Always enabled.
- Refund & Return Policy — An optional, scrollable Refund & Return Policy can be enabled in Settings. When enabled, bidders must read and accept it during auction approval.
- Chargeback Waiver — An optional, scrollable Chargeback Waiver can be enabled in Settings. When enabled, bidders must read and accept it during auction approval.
- Admin Management — New "Legal Agreements" page under the Bidspirit admin menu with tabbed TinyMCE editors for each agreement type. Includes automatic version numbering (incremented on content change) and full version history.
- Consent Logging — Every agreement acceptance is logged to a dedicated database table (
af_user_agreement_log) with the agreement type, version, user email, IP address, user agent, auction ID, and timestamp. - User Tracking Integration — Agreement events (
terms_agreement,refund_agreement,chargeback_waiver) are also recorded in the existing IP tracking system alongside registration, login, and bid events. - Placeholder Content — Default sample content is seeded on plugin activation for all three agreement types.
Settings Added
- Enable Refund & Return Policy — Toggle to require bidders to accept the refund policy during auction approval.
- Enable Chargeback Waiver — Toggle to require bidders to accept the chargeback waiver during auction approval.
Database
- New table:
af_legal_agreements— Current active agreement content per type - New table:
af_legal_agreement_versions— Version history archive - New table:
af_user_agreement_log— User consent records
Files Changed
- Modified:
auctionforge.php,inc/controllers/Settings.php,inc/controllers/BidspiritViews.php,inc/ip-logger.php,templates/js-chunks/approval-info.php,assets/js/app.js - Created:
inc/legal/class-legal-agreements.php,admin/view/legal-agreements.php
---
[3.5.0.6] — 2026-04-08
Bid Event Tracking
Features
- Bid Tracking — All successful bids (regular, catalog, pre-sale buyout, post-sale purchase) now fire
afLogIP("bid", bidspiritUser)to capture the bidder's full identity in the user tracking table. - Whitelist Update — Added
bidto the allowedevent_typevalues in both the local plugin and the central WPDeploy API.
---
[3.5.0.5] — 2026-04-08
Self-Healing Database Schema
Features
- Auto-Migration — The plugin now auto-detects and adds any missing tracking table columns on version upgrade, ensuring sites with older schemas seamlessly migrate without manual SQL.
---
[3.5.0.4] — 2026-04-08
API Key Auto-Healing
Features
- Seamless Self-Registration — The WordPress plugin now autonomously regenerates and saves a fresh API Key whenever WPDeploy rejects a payload with an
api_key_collisionerror. This guarantees zero-downtime security handovers when developers clone instances to proxy/staging servers.
---
[3.5.0.3] — 2026-04-08
API Key Collision Defense
Features
- 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_collisionerrors, directly instructing developers to update cloned keys.
---
[3.5.0.2] — 2026-04-08
Modal Trigger Hotfix
Fixes
- Restructured internal UI rendering priority to gracefully deploy the inline Modal triggers inside custom IP log view without colliding with cached
z-indexstacks.
---
[3.5.0.1] — 2026-04-08
Hotfix
Fixes
- Timed Auction Badge Visibility — Fixed a strict type-matching bug in the main
auction_list.phpcore file that incorrectly hid the "Timed Auction" badge overlay from valid timed/online auctions on the main upcoming/archive views. The badge now displays properly across all manual and Bidspirit-synced objects when toggled on.
Files Changed
- Modified:
templates/main/auction_list.php
---
[3.2.9.1] — 2026-03-30
Timed Auction Display Enhancements
Features
- Timed Auction Countdown Text Toggle — Added a WP-Admin setting "Change text to 'Auction will close in'" that conditionally changes the countdown label for timed/online auctions on single lot pages.
- Shortcode Text Toggle Support — Extended the new countdown text logic to the
bp_upcoming_wideshortcodes so "Live bidding starts in:" successfully transitions to "Auction will close in:" for timed auctions.
Files Changed
- Modified:
inc/controllers/Settings.php,templates/single-lot.php,templates/shortcodes/upcoming-auction-wide.php,templates/shortcodes/upcoming-auction-wide-manual.php
---
[3.2.9.0] — 2026-03-29
Billing & Invoices Polish
Fixes
- Profile Invoice ID Tracking — Prevented internal auction codes (e.g.
002orai4) from breaking into the clean hyphenated titles inside theprofile-templates.phpview. - Dynamic Payment Statuses — Replaced Bidspirit's default/cached
NOT PAIDHTML payloads by wiring thedompdfgenerator to directly respect the current$b.statusstring from the API (resolving instances where a paid invoice still printed "NOT PAID" atop the document). - Payment Instructions Conditional — Automatically hide the "Payment Instructions" block from the PDF footer when an invoice is fully paid.
- Improved Nomenclature — Changed "Invoice No:" to "Bidder No:" on document output to prevent confusion with static invoice ledger IDs.
---
[3.2.6.0] — 2026-03-28
Multi-Day Auction Lot Filtering Fix
Fixes
- Day 2+ showing lots from Day 1 in multi-day auctions — The
itemIndexcolumn inbp_meta_dataisvarchar(55), but the day-range filter inBidspiritQuery::bp_query_where()was comparing it as a string. With string comparison, lot numbers like'11','101'–'145'incorrectly fell between'1001'and'1450', causing Day 1 lots to leak into Day 2 results. Fixed by usingCAST(bpMeta.itemIndex AS UNSIGNED)for numeric comparison andintval()on the PHP-side boundary values. Letter lots (e.g.14A,1025A) are handled correctly —CASTstrips the suffix, keeping them grouped with their base lot number.
Files Changed
- Modified:
inc/controllers/BidspiritQuery.php
---
[3.2.5.9] — 2026-03-27
Catalog Page Fix
Fixes
- Duplicate preview hours on catalog pages — The
displayHoursfield was rendered twice: once via thebp_after_description_auctionhook inBidspiritViews.phpand once inline in the auction template. Removed the hook-based rendering to eliminate the duplication.
Files Changed
- Modified:
inc/controllers/BidspiritViews.php,templates/main/auction.php
---
[3.2.5] — 2026-03-19
Sync Reliability & Stuck Lot Prevention
Fixes
- CATALOG_PUBLISHED webhook now triggers catalog sync — Previously only sent push notifications without syncing lots. When the earlier AUCTION_CATALOG_UPDATED fired before the catalog was ready on BidSpirit, lots were never imported. CATALOG_PUBLISHED now calls
auctionCatalogUpdated()to trigger a full catalog sync when the catalog is actually available. - 0-lot API results now fail instead of silently succeeding — When BidSpirit API returns 0 lots (catalog not yet ready), the sync job now fails with an explicit error message, allowing the next webhook to create a fresh retry job.
- Expanded CDN allowlist in pre_http_request filter — The HTTP filter during bulk post insertion now allows all
*.bidspirit.comsubdomains and BidSpirit image CDNs (fastly.net,cloudfront.net). Previously onlybidspirit.comandwww.bidspirit.comwere allowed, blocking image downloads during sync and causing worker hangs. - InsertLotsBS timeout guard — Stage 5 (InsertLotsBS processing loop) now has a 180-second timeout and logs progress every 2 batches. Prevents indefinite hangs that previously required manual force-kill.
- fixResult() no longer marks lots as done when postId=0 — When
lotProcessing()fails to create a WP post, the staging row now keepssyncFinished=0so the lot is retried on the next sync pass, instead of being permanently marked as complete with no actual post. - lotProcessing() logs error on missing auction term — Previously returned 0 silently when
Auction::findAuctionById()failed. Now logs an explicit error that feeds intofixResult()to keep the lot retryable. - Hourly orphan detection in safety cron — New step in
syncSafety.phpdetects lot posts that exist inbp_meta_databut are missing their auction taxonomy assignment (caused by workers killed mid-batch) and auto-repairs them withwp_set_object_terms().
Files Changed
- Modified:
inc/controllers/AuctionsAPI.php,inc/sync/CatalogSyncWorker.php,inc/abs/InsertLotsAbstract.php,inc/import/InsertLotsBS.php,crontasks/syncSafety.php
---
[3.2.4] — 2026-03-18
Sync Worker Hang Fix
Fixes
- Sync workers hanging at InsertLotsBS stage — Third-party plugins (Smush Pro, SmartCrawl SEO, WPMU DEV Updates) hook into
wp_insert_post()and make blocking outbound HTTPS calls for every lot processed. With 489+ lots per auction, this caused workers to hang indefinitely on socket reads to WPMU DEV servers (32.193.94.25,32.193.93.106). AddedWP_IMPORTINGconstant at the REST worker entry point and apre_http_requestfilter inCatalogSyncWorkerthat blocks all non-essential external HTTP during the batch post-insertion phase. Loopback (127.0.0.1,localhost) and BidSpirit API calls remain allowed. - Stuck staging rows after force-kill — When workers were force-killed mid-sync, staging rows in
import_historywere left withsyncstart=1and never unblocked. Subsequent sync runs could not see these rows (filtered out byLot::getRawLots()), causing the InsertLotsBS loop to exit immediately with 0 posts processed. Combined with job deduplication (SyncQueue::enqueue()skips if aprocessingjob exists), this created a deadlock where no new sync could proceed.
Files Changed
- Modified:
auctionforge.php,inc/sync/CatalogSyncWorker.php
---
[3.2.2] — 2026-03-17
Full Sync Auction Discovery Fix
Fixes
- Full Sync finds no auctions on fresh sites — The v3
full_syncaction only queried the WordPress database for existing auction terms, but on a freshly deployed site the database has zero auctions. AddedAuctionList::init()discovery step before querying the DB, so Full Sync now fetches all auctions from the BidSpirit API and creates taxonomy terms first, then enqueues catalog sync jobs for each.
Files Changed
- Modified:
auctionforge.php
---
[3.2.0] — 2026-03-14
Webhook Pipeline Fixes, Archive Sync & Admin UI Overhaul
New Features
- Archive Sync — New "Archive Sync" button on Sync Status admin page. Enqueues catalog sync jobs for all ARCHIVED/ENDED auctions. Past auctions now appear in the auction dropdown with an optgroup separator and state label.
- Sync Tasks v3 — Replaced old v2 task cards (importData, importBidSpirit, lotBidSpiritOld) with v3 queue-based tasks. "Sync Active Auctions" and "Sync Archived Auctions" now enqueue jobs via the queue system. Maintenance tasks (Clean Draft/Trash Lots, Clean Orphaned Meta) remain as direct-execution tasks.
- How It Works guide rewritten — Complete rewrite of the admin guide for v3 architecture. Documents webhook-first flow, all 5 job types, queue system mechanics, cron setup (external + WP-Cron), configuration constants, and troubleshooting.
Fixes
- Dual-write removed — Removed legacy handlers from
auctionCatalogUpdated(),auctionDayEnded(), anditemsUpdated()webhook methods. The old handlers were racing with the v3 worker, creating orphaned staging rows inimport_historythat were never processed. All three methods now exclusively use the v3 enqueue → spawn path. - ITEMS_UPDATED webhook — Fixed
itemsUpdated()failing to enqueue jobs. TheITEMS_UPDATEDpayload hasauctionIdnested initemsByLanguage.{lang}[0].item.auctionId, not at the top level. Added extraction logic to resolve it. - ItemUpdateWorker incomplete —
ItemUpdateWorker::process()was only callingLot::bulkSave()(staging table) without runningInsertLotsBSto process staged data into WP posts andbp_meta_data. Added the InsertLotsBS processing step with autocommit restore. Item updates now flow: stage → InsertLotsBS → WP post + meta → cache clear. - Worker spawn reliability — Changed
SyncQueue::spawnWorker()from non-blocking HTTPS to blocking HTTP loopback (http://127.0.0.1with explicitHostheader, 2s timeout). Fixes nginx 403/404 errors when HTTPS loopback hits the default vhost instead of the site's vhost. - API token constant — Plugin expects
AUCTIONFORGE_API_TOKENinwp-config.php(renamed fromUCO_API_TOKENduring the plugin rename). Documented in readme.
Database
- DB version: 22 → 23
Files Changed
- Modified:
inc/controllers/AuctionsAPI.php,inc/sync/ItemUpdateWorker.php,inc/sync/SyncQueue.php,auctionforge.php,admin/view/sync-status.php,readme.txt
---
[3.0.0] — 2025-03-14
New Feature: Webhook-First Sync Architecture (Sync v3)
Overview: Complete redesign of the BidSpirit data synchronisation pipeline. Replaces the old two-phase polling system (importBidSpirit every hour + importData every minute) with a webhook-driven job queue that processes data in near real-time.
Architecture
- 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: webhook → queue → background worker → WordPress posts. - Dual-write mode — During transition, webhooks enqueue jobs AND still run the legacy handlers. Once verified, legacy handlers can be removed cleanly.
- Job deduplication — Prevents duplicate work by checking for existing pending/processing jobs with the same auction_id + job_type.
New Components
- Job Queue System (
inc/sync/SyncQueue.php) — Priority-based FIFO queue with atomic job claiming, status tracking (pending/processing/completed/failed/skipped), worker PID tracking, and automatic stuck job recovery. - Sync Logger (
inc/sync/SyncLogger.php) — Real-time log table for admin console polling with level filtering (info/success/warning/error) and incremental cursor-based retrieval. - Catalog Sync Worker (
inc/sync/CatalogSyncWorker.php) — Processes catalog_sync, full_sync, and day_ended jobs by reusing existingLotList::singleRun()logic. - Item Update Worker (
inc/sync/ItemUpdateWorker.php) — Processes individual item_update jobs with the same logic as the webhookitemsUpdatedhandler. - Background Worker (
crontasks/syncWorker.php) — Async CLI process spawned by webhooks viaexec()or by the safety cron. Claims and processes queued jobs with a configurable timeout (default 240s). - Safety Net (
crontasks/syncSafety.php) — Hourly cron that resets stuck jobs (>10min), spawns workers for pending jobs, runs a 24-hour health check (auto-enqueues full sync if no webhooks received), and purges old data.
Admin UI
- Queue Status Dashboard — New card on Sync Status page showing pending/processing/completed/failed/skipped counts, recent jobs table with real-time refresh, worker status badge, and action buttons:
- Full Sync — Enqueues catalog sync for all active auctions
- Sync Selected — Enqueue a single auction from dropdown
- Spawn Worker — Manually trigger a background worker process
- Live Console — Dark-themed terminal console on the Sync Status page. Polls
af_sync_logevery 1.5s showing timestamped, color-coded log entries from webhooks, workers, queue operations, and the safety cron. Supports pause, clear, and auto-scroll.
Cron Changes
- Removed
importData(ran every minute — ~1,440 PHP executions/day) - Removed
importBidSpirit(ran hourly — ~24 PHP executions/day) - Added
syncSafety(runs hourly at :10 — 24 PHP executions/day) - Net effect: ~62 PHP executions/hour → 1 PHP execution/hour
- WP-Cron safety hook (
auctionforge_sync_safety) — Always-active hourly event, independent of external cron - setup.sh v3 — Updated task definitions, new
migratecommand for interactive v2→v3 transition
Database
- New table:
af_sync_queue— Job queue with status, priority, source, attempts, worker PID, timing columns - New table:
af_sync_log— Real-time log entries with context, level, auction_id, job_id - DB version: 20 → 22
Constants Added
| Constant | Default | Description |
|---|---|---|
|
AUCTIONFORGE_SYNC_WORKER_TIMEOUT| 240 | Worker process timeout in seconds ||
AUCTIONFORGE_SYNC_STALE_JOB| 600 | Seconds before a processing job is considered stuck ||
AUCTIONFORGE_SYNC_HEALTH_CHECK| 86400 | Seconds without webhook before triggering full sync ||
AUCTIONFORGE_SYNC_LOG_RETENTION| 7 | Days to keep log entries ||
AUCTIONFORGE_SYNC_QUEUE_RETENTION| 30 | Days to keep completed queue jobs ||
AUCTIONFORGE_CURL_TIMEOUT| 30 | BidSpirit API cURL timeout in seconds ||
AUCTIONFORGE_PHP_BINARY| /www/server/php/83/bin/php | PHP CLI binary path for spawning workers |AJAX Handlers Added
auctionforge_sync_log_poll— Incremental log polling for live consoleauctionforge_sync_queue_status— Queue counts + recent jobs for dashboardauctionforge_sync_enqueue— Admin-triggered sync actions (full_sync, sync_auction, spawn_worker)
Fixes
- cURL timeout — BidSpiritRequest now enforces a 30-second timeout (was unlimited/0), preventing hung connections from blocking the sync pipeline.
Files Changed
- Modified:
auctionforge.php,inc/coreIncludes.php,inc/controllers/AuctionsAPI.php,inc/BidSpiritRequest.php,admin/view/sync-status.php,crontasks/setup.sh - Created:
inc/sync/SyncQueue.php,inc/sync/SyncLogger.php,inc/sync/CatalogSyncWorker.php,inc/sync/ItemUpdateWorker.php,crontasks/syncWorker.php,crontasks/syncSafety.php
---
[2.7.3.0]
Fixes
- Various stability improvements and bug fixes.
[2.7.1.2]
Fixes
- Added missing
vatAndCommission()function inloadBid()— the sales tax display on single lot pages was never being rendered because the code to callloadTemplateforvat-and-commission-templatewas missing fromapp.js.
[2.7.1.1]
Fixes
- 2 decimal places now only appear in the bid modal (Your max bid, Total Price) via
showDecimalsflag. 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.
[2.7.0.9]
Fixes
- Fixed fatal error during plugin install/upgrade:
class-stats-database.phprequire failure.
[2.7.0.0]
New Features: Advanced Lot Analytics
- Conversion Tracking, Peak Viewing Times, Pre-Sale vs Live Comparison, Category Performance, Share Analytics, Search → View Funnel, Click-Through Tracking, CSV Export, Hot Lot Badge.
- New DB table:
af_lot_shares. New columns onaf_lot_analytics. DB version bumped to 20.
[2.6.0.0]
New Feature: Lot Analytics
- Comprehensive lot view and favorite tracking system with admin dashboard.
[2.5.0.0]
New Features
- Site Statistics System — Full website analytics built into the plugin admin.
- Recently Viewed Items — Profile page tab showing last 20 viewed lots per user.
- Run Identity Check — calls the new wpdeploy
-
v3.7.0.23 Stable May 07, 2026Download v3.7.0.23📦 9 MB⚙️ WP 5.2+🔧 PHP 7.2+✓ Tested 6.4
AuctionForge Changelog
All notable changes to the AuctionForge plugin are documented in this file.
---
[3.7.0.21] — 2026-05-05
Added — Connection Diagnostics on the Updates admin page
A new Connection Diagnostics card on Lots → Updates that detects and one-click-heals identity mismatches between this site and the deployment server.
The problem it solves. When a WordPress install is cloned (template → customer site, dev → prod, backup → restore), the cloned wp_options carry the original site's
auctionforge_update_api_keyover to the newhome_url(). The new install then makes API calls to wpdeploy *authenticated as the original site*. wpdeploy looks up by api_key, not by URL, so every/sync-user-tracking,/check-updates,/report-health, and most importantly the Kuma push URL, gets recorded against the WRONGwpdeploy.sitesrow. The cloned site's monitor stays silent; the original's monitor shows traffic that isn't from it.What the diagnostic does:
- Run Identity Check — calls the new wpdeploy
GET /api.php/whoamiendpoint and compares the returnedcaller_site_urlagainsthome_url(). Renders a verdict ("matches" / "MISMATCH") plus the full server-side view (site_id, site_name, last_check, plugin version on file, remote IP). The "Re-register & Reset Kuma" button only appears if there's a mismatch. - Re-register & Reset Kuma — calls
/request-access(which is idempotent onsite_url— wpdeploy returns the canonical api_key for *this*home_url(), regardless of whatever wrong key we were holding), wipesauctionforge_kuma_push_urland any leftover heartbeat cron events, then immediately fires/check-updatesso the api_request interceptor catches the freshly-correct kuma_push_url for *this* site. The keepalive mu-plugin's heartbeat picks it up on the next 60s tick.
Internal
AuctionForge_Auto_Updater::whoami()(new) — thin wrapper overapi_request('whoami', [], 'GET'). Returns the parsed wpdeploy/whoamipayload.AuctionForge_Auto_Updater::reset_connection()(new) — three-step heal: re-register → wipe Kuma cached state → re-fetch via/check-updates. Returns shape suitable forwp_send_json_success.- Two new AJAX actions:
auctionforge_diagnose_connection,auctionforge_fix_connection. Both behindmanage_optionscapability + nonce check. auctionforge_normalize_host()helper for case/scheme/www-tolerant URL comparison.
Server-side companion
Requires the wpdeploy
/api.php/whoamiendpoint added in the same release window. The endpoint is gated behind whatever api_key the caller already presented (a master key returnstype=masterwith no site row; a per-site key returns the site row that key resolves to). Reveals nothing the caller doesn't already implicitly authenticate against.---
[3.7.0.20] — 2026-05-04
Changed
- Kuma heartbeat path is now wpdeploy-independent. The actual heartbeat firing — wp-cron schedule, page-load piggy-back, outbound HTTP — moved out of AF and into the AuctionForge Keepalive mu-plugin (
wp-content/mu-plugins/auctionforge-keepalive.php, bumped to v1.2.1). Once a site has been provisioned once andauctionforge_kuma_push_urlis cached locally, the heartbeat keeps reporting forever even if AF is deactivated, mid-upgrade, deleted from disk, or wpdeploy is offline. The mu-plugin can't be deactivated by WordPress, can't be broken by an AF release, and depends on AF for nothing. - AF only writes the
kuma_push_urloption now. It no longer schedules the cron, no longer fires the heartbeat, and no longer holds any heartbeat-related state. Theapi_request()interceptor still catcheskuma_push_urlfrom/check-updatesand/report-healthresponses and persists it; the mu-plugin reads it from there. - Migration block.
init_hooks()clears any leftoverauctionforge_kuma_heartbeatwp-cron event from AF ≤ 3.7.0.19 on first plugin load after upgrade. The mu-plugin runs the same clear on its ownplugins_loadedhook — belt and braces. The new event the mu-plugin schedules iskuma_heartbeat_tickon a newkuma_60sschedule. AuctionForge_Auto_Updater::kuma_heartbeat()no-opped. Kept as a safety landing pad so any staleauctionforge_kuma_heartbeatwp-cron event that fires one last time before migration kicks in doesn't trip a "no callback registered" warning. Real heartbeat work happens in the mu-plugin.
Added — operator override
AUCTIONFORGE_KUMA_PUSH_URLconstant. Define it inwp-config.phpto point a site directly at Kuma without ever involving wpdeploy:
```php
define('AUCTIONFORGE_KUMA_PUSH_URL', 'https://kuma.example.com/api/push/<token>?status=up&msg=&ping=');
```
The constant takes precedence over the
auctionforge_kuma_push_urloption. With it set, the site can be operated fully outside wpdeploy — useful for one-off installs, customer-managed sites, or disaster-recovery scenarios where wpdeploy is unreachable for an extended period.Internal — Keepalive mu-plugin v1.2.1
The bundled keepalive template at
inc/keepalive/auctionforge-keepalive.template.phpnow also handles Kuma heartbeats. Three layered triggers ensure cadence stays tight regardless of site traffic:1. Dedicated wp-cron event
kuma_heartbeat_tickon a new 60-secondkuma_60sschedule2. Page-load piggy-back on
init: any request older than 50s since the last beat fires another, transient-guarded so concurrent hits coalesce. Free on busy sites; rescues low-traffic sites the moment any visitor arrives.3. Self-heal inside the cron callback: if the event somehow gets cleared, re-arm it before sending the beat.
HTTP is
timeout=2, blocking=false— fire-and-forget, never slows page loads. External IP introspection (ipify → ifconfig.me → icanhazip fallback chain, 24h transient cache) is duplicated in the mu-plugin so it doesn't depend on AF being loaded for the IP lookup.The keepalive installer (
class-keepalive-installer.php) detects theKEEPALIVE_VERSION: 1.2.1header bump and idempotently overwrites every site's mu-plugin on the next AF load. No manual reactivation needed.Failure modes after this release
| State | Heartbeat? |
|---|---|
| AF active and healthy | ✅ via mu-plugin |
| AF deactivated by an operator | ✅ mu-plugin runs anyway |
| AF deleted from disk | ✅ as long as
auctionforge_kuma_push_urloption exists OR constant is set || AF mid-upgrade / partial install | ✅ mu-plugin doesn't depend on AF code paths |
| wpdeploy down (existing site) | ✅ option is cached locally, no wpdeploy round-trip |
| wpdeploy down (brand-new site, never provisioned) | ❌ first-time URL provisioning still needs wpdeploy. One-shot, accepted trade-off. |
| Site has zero traffic AND wp-cron isn't firing | ❌ truly nothing to trigger a beat. Mitigation is OS-level cron / DISABLE_WP_CRON, out of scope here. |
---
[3.7.0.19] — 2026-05-04
Changed
- Reverted Kuma heartbeat cadence: 3 min → 1 min.
auctionforge_kuma_heartbeatis back on thebp_minutelyschedule. With Kuma's 310s silence window, 60s cadence tolerates 4 missed wp-cron ticks before flipping a monitor red — the original "give-it-leeway" semantics. The 3-min cadence introduced in 3.7.0.18 was strictly less chatty but tighter (a single missed tick would trip Kuma), and the trade-off wasn't worth it operationally. - Migration block updated.
init_hooks()now detects any existing event scheduled on a non-bp_minutelycadence (e.g. thebp_3_minutelyset by 3.7.0.18) and re-schedules ontobp_minutely. Sites that took 3.7.0.18 roll back automatically on first plugin load after upgrade. - First-fire jitter narrowed back to 0–60s to match the new cadence.
Notes
- The
bp_3_minutelycron schedule registration inauctionforge.phpis kept (harmless; available for future use). Only the heartbeat scheduling sites have been reverted. - Apparent latency in Kuma flipping a monitor red after a real outage is governed by Kuma's per-monitor
interval(silence-detection window, currently 310s on the wpdeploy/Kuma side), not by this cron's cadence. To detect outages faster, lower the Kumainterval; to add more tolerance to wp-cron drift, raise it.
---
[3.7.0.18] — 2026-05-04
Changed
- Kuma heartbeat cron cadence: 1 min → 3 min.
auctionforge_kuma_heartbeatnow runs on a newbp_3_minutelyschedule (180s) instead ofbp_minutely(60s). This pairs with Kuma's 310s silence-detection window — a single late wp-cron tick (3 min + drift) still lands inside the threshold, but normal traffic to Kuma drops by ~3×. - Random first-fire offset widened from 60s → 180s. With ~50 sites on a single Kuma instance, spreading first-fires across the full 3-min window prevents synchronised bursts every 3 minutes.
- Auto-migration of existing scheduled events. On plugin upgrade
init_hooks()callswp_get_scheduled_event('auctionforge_kuma_heartbeat')and, if the existing event is onbp_minutely, clears it and reschedules ontobp_3_minutely. Idempotent — a no-op once migrated.
Internal
- New cron schedule registered:
bp_3_minutely(BP_MINUTELY * 3= 180s). Defined alongside the existingbp_minutely/bp_ten_minutely/bp_hourly/bp_24_hourlyschedules inauctionforge.php.
---
[3.7.0.17] — 2026-05-04
Fix: "Install Now" always returned
up_to_dateThe
/sync/versionREST endpoint (called by wpdeploy's Install Now button) was always respondingsuccess: false, reason: up_to_dateregardless of the actual installed version, defeating the button's whole purpose.Root cause
rest_force_plugin_update()did:```
delete_site_transient('update_plugins');
$this->check_pending_updates();
$updates = get_site_transient('update_plugins');
```
check_pending_updates()calls the/pending-updatesendpoint on wpdeploy (which returns the deploy queue), but it does not touch the WPupdate_pluginstransient. The transient just got deleted on the line above and never gets re-populated, so theisset($updates->response[…])check always failed → always returnedup_to_date.Fix
- Use
wp_update_plugins()instead — that's what fires thepre_set_site_transient_update_pluginsfilter chain that AF's owncheck_for_updates()callback hooks into to seed the transient. Same pattern is already used correctly ininstall_update()at line 280. - Belt-and-braces: when the request body carries an explicit target
versionand that version is strictly greater than the on-disk plugin version (perversion_compare), bypass the transient check and force the install. This handles edge cases where the transient seeding fails (network blip during the wp-cron cycle, hosting-side cache, etc.) so the explicit Install Now command still does what it says.
---
[3.7.0.16] — 2026-05-04
Server external IP reported to wpdeploy + included in Kuma heartbeats
Each AF install now reports its server's outbound external IP. Two channels:
1. Kuma heartbeat
msg— the per-minute push payload now reads<wp_version>|<plugin_version>|<external_ip>(e.g.6.9.4|3.7.0.16|152.53.187.82) so you can spot at a glance which physical box each site lives on. When a host goes dark, multiple monitors flip red simultaneously with the same IP — instant root-cause hint.2.
/report-healthpayload — a newexternal_ipfield that wpdeploy stores onsites.external_ip. Visible in the Sites admin view as a tappable IP chip; clicking it filters the table to all sites sharing that IP.How the IP is detected
AuctionForge_Auto_Updater::get_external_ip()calls one of three public echo services in turn —api.ipify.org,ifconfig.me/ip,icanhazip.com— with a 4-second timeout each. The first one that returns a valid IP wins. Result is cached in a transient for 24 hours so we don't hit external services on every report cycle.Wpdeploy fallback for older plugins
/report-healthnow also capturesREMOTE_ADDR(orHTTP_CF_CONNECTING_IPwhen behind Cloudflare) when the payload doesn't includeexternal_ip. So sites still on 3.7.0.15 or older start populating their IP today via the same route, no plugin update needed for that data path.---
[3.7.0.15] — 2026-05-04
Kuma monitors land in an "Unallocated" group by default
New AuctionForge installs are auto-enrolled into Kuma under a new top-level group called Unallocated so the operator can review them and drag-drop into the right home (Bidspirit Auction Sites, Stephen's Auctions, Misc Websites, etc.) before classification. Without this every new monitor would appear at the dashboard top level alongside whatever group hierarchy already exists.
What changed (wpdeploy-side, no plugin behaviour change)
KumaProvisionernow ensures an "Unallocated" group exists in Kuma (find-or-create via the same Socket.IOaddpath used for monitors, withtype='group') before provisioning each new push monitor, and passesparent=<group_id>in theaddpayload so the new monitor lands inside it.- The Node helper accepts arbitrary
typeandparentfields on the input payload (previously hardcoded totype='push'). - The group itself gets the same
user_id=1reassignment so it shows up on the human admin's dashboard.
Existing Clumber monitor (id=71) was migrated into the new group as part of this release.
This is a wpdeploy infrastructure change — the AF plugin code is unchanged from 3.7.0.14. Version bumped only to mark a clean snapshot point.
---
[3.7.0.14] — 2026-05-04
Uptime Kuma push heartbeat with automatic enrolment
Each AF install now appears as its own monitor on the central Uptime Kuma at https://kuma.smoothbyteit.dev, beating every minute and flipping red within ~90 seconds when a site goes dark. Auto-enrolled — no manual Kuma UI clicks per site.
How it works
1. First contact: when the plugin calls
/request-accessor/report-health, wpdeploy's newKumaProvisioneropens a Socket.IO connection to Kuma as a dedicatedauctionforge-botuser, calls the officialaddevent, and gets back a fresh push token. The resulting URL is shipped to the plugin in the JSON response askuma_push_url.2. Plugin-side: a generic interceptor on
api_request()persistskuma_push_urlto the optionauctionforge_kuma_push_urlwhenever it appears in any wpdeploy response, and immediately schedules the newauctionforge_kuma_heartbeatcron on the existingbp_minutelyinterval.3. Heartbeat: the cron handler sends a single
wp_remote_getto the push URL each minute withmsg=<wp_version>|<plugin_version>so Kuma's dashboard shows the running stack at a glance. Kuma's silence-detection window is 90s, so a single missed wp-cron tick won't false-DOWN.4. Idempotency: the Kuma monitor's
descriptionfield storeswpdeploy_site_id:<id>. Re-registering the same site short-circuits at the wpdeploy layer (existingkuma_monitor_idonsites), or — if that's missing — Kuma's existing row is reattached via the description anchor. Re-installing the plugin never duplicates monitors.Why Socket.IO and not direct DB insert
Kuma's monitor scheduler does not poll its own DB for new rows —
startMonitors()only loads monitors at boot, and new ones are armed via the authenticated Socket.IOaddevent handler (which callsstartMonitor()and arms the per-monitorsafeBeatsetTimeout). A direct INSERT would create a "phantom" monitor that accepts pushes but never flips DOWN on silence, defeating the whole feature.Notifications + monitor ownership
Provisioner reads existing Kuma notification rows whose channel is Telegram (or marked default-for-new-monitors) and attaches them to every new monitor via the
addevent'snotificationIDList. After the Socket.IOaddsucceeds, the provisioner direct-writesuser_id=1to the new monitor row in Kuma's SQLite — Kuma'saddhandler hardcodesuser_id=socket.userID(the bot at user 2), which causes the frontend's real-time monitor-list updates to skip the admin's session. The follow-up UPDATE stamps ownership to the human admin so monitors render with their full name on the admin dashboard immediately.Failure modes
Every call boundary degrades safely. If Kuma is unreachable when a site registers, registration completes without
kuma_push_url; the next twicedaily/report-healthretries. Heartbeat HTTP failures are silent (which is the desired outcome — Kuma's silence-detection is the signal). Kuma reset / monitor row deleted: provisioner's pre-flight check NULLs the wpdeploy anchors and falls through to fresh provisioning on the next call.Operator setup
Already done: the
auctionforge-botKuma user has been created and credentials populated in wpdeploy'sconfig.php. To rotate or migrate Kuma later, editKUMA_URL/KUMA_BOT_USER/KUMA_BOT_PASSinconfig.php— no plugin redeploy needed.---
[3.7.0.13] — 2026-05-04
Wide shortcode: hide Register button for logged-in users
- When a user is logged in to BidSpirit (
body.bp-login), the Register button is now automatically hidden on wide-format auction cards (bp_upcoming_wideandbp_auction_list layout="wide"). - The View Catalog / Catalog Coming Soon button expands to full width when the Register button is hidden.
- Uses a lightweight
MutationObserverto react to BidSpirit's async session init. - Applied to both
UpcomingAuctionWide.phpandAuctionList.phpshortcode CSS blocks.
---
[3.7.0.12] — 2026-05-03
Stop-word denylist for BidSpirit category-tag concatenations
BidSpirit's
wp_bp_meta_data.tagsfield arrives as PascalCase category names lowercased without separators (uscollectibles,firearmsaccessoriesammunition,usdecorativearts,printsandmultiples). They look like keywords but they're really categories, and on sites where the tags field is populated they completely swamp the top-5 chips for power users (e.g. one buyer's profile was led byuscollectibles 453 viewsdespite that being a label rather than a real interest signal).29 known patterns added to
stop-words.phpso the tokenizer drops them at extraction time. New ones surfacing from sites we haven't seen yet should be added here as they appear; the wpdeploy?tab=keywordscorpus page makes them easy to spot (sort by most users with low lots count and look for non-word concatenations).---
[3.7.0.11] — 2026-05-03
Keyword extractor — capture model years + hyphenated calibers, drop more auction noise
The People view's top-5 keyword chips were filling up with generic descriptors (
household,model,original,assortment) instead of the brand/maker terms (mauser,whitworth,colt) that actually distinguish one buyer from another. Live-data review on the new?tab=keywordsKeyword Corpus page on wpdeploy confirmed the cause: real signal was being lost at the tokenizer stage.Tokenizer changes (
inc/stats/class-keyword-extractor.php)Three pre-passes now run before the standard split-on-non-alpha:
1. Hyphenated / x-separated calibers —
.45-70,.30-06,7.62x54r,8x57. Without this they're split into pure-digit fragments and dropped, losing the actual model identifier.2. Caliber-with-suffix —
9mm,.22lr,.45acp,.380acp. Previously only survived by accident because of the trailing letters; now extracted explicitly.3. 4-digit model years 1700–2099 —
1873,1903,1911,1971. Pure-digit tokens were unconditionally dropped; now retained when year-shaped.Standard pass relaxed to allow 4-digit pure-digit tokens between 1700 and 2099.
Stop-word additions (
inc/stats/stop-words.php)Conservative — only universally empty auction descriptors:
original,marked,accessories,decorative,household,goods,made,condition,assortmentDeliberately NOT added:
antique,vintage,rare,fine— those carry buyer-segmentation signal (antiquarian buyers vs. modern-collectibles buyers). Borderline cases (metal,wooden,american,model) are left to the wpdeploy-side IDF re-rank.Companion change on wpdeploy (no plugin update needed)
refresh_people_rollup.phpnow multiplies each keyword's score by an IDF factor pulled fromkeyword_idf(refreshed hourly byrefresh_lot_keyword_index.php). Generic keywords that appear in many lots get demoted automatically; brand/maker words that only appear on a handful get lifted into the top-5 chips.After deploying this version, reset the
auctionforge_lots_sync_watermarkoption on each site and clear thewp_af_stats_lot_keywordstable to force re-extraction of every lot through the new tokenizer.---
[3.7.0.10] — 2026-05-03
Lots sync — ship resolved CDN image URL, not bare BidSpirit filename
class-lots-sync.phpwas sendingimagesListStr's first comma-token verbatim asimage_url— that's the raw BidSpirit storage value (e.g.001.jpg). Wpdeploy received a bare filename, the browser resolved it against the wpdeploy host, and every lot thumbnail 404'd.The lots-sync now instantiates
LotImageand pulls the resolved CDN URL (LABEL_MEDIUMthumbnail), with fallback toLABEL_ORIGINALand a final defensive check that drops anything that doesn't start withhttp(s)://. Resolution is wrapped in try/catch — a missing class or BidSpirit settings issue leavesimage_urlempty rather than blowing up the sync batch.After deploying this version on a site, reset its
auctionforge_lots_sync_watermarkoption (delete the row) to re-push existing lots through the new resolver. The wpdeploy view skips<img>rendering whenimage_urlisn't a real URL, so dirty rows degrade silently while the watermark catches up.---
[3.7.0.9] — 2026-05-03
Keepalive sweep — auto-clears WP upgrader debris that produces silent "Could not create directory" failures
WordPress 6.x's atomic-rollback flow leaves
wp-content/upgrade-temp-backup/lying around when its post-install cleanup misfires (the user-facing symptom is "Update failed: Could not create directory" after an update that has actually already succeeded). Stalewp-content/upgrade/<plugin>-tmp/and.maintenancelockfiles from crashed upgrades cause the *next* upgrade attempt to fail the same way. None of WP's own scheduled cleanup catches these reliably.The keepalive mu-plugin (
KEEPALIVE_VERSION1.1.0) now sweeps all three classes of debris on every page load, transient-guarded to once per hour. Safety thresholds prevent it touching anything actually in flight:.maintenancefiles less than 5 min old,wp-content/upgrade/*entries less than 60 min old, andupgrade-temp-backup/less than 30 min old are left alone. Wrapped in try/catch with no throws, so the sweep can never block a request.The keepalive installer detects the version bump and rewrites
wp-content/mu-plugins/auctionforge-keepalive.phpautomatically on the next AF load, no manual reactivation needed.---
[3.7.0.8] — 2026-05-03
Shop auction UI refinements & share button settings
Shop (Buy-It-Now) catalog improvements
- Shop sorting dropdown: Added a dedicated sorting dropdown for shop catalogs with options: Recently Added, Price: High, and Price: Low. Sorts by
buyoutPricemetadata. Regular auction catalogs retain the original sorting options. - Removed "Buyout price:" label: On shop lot pages, the redundant "Buyout price:" text before the price is now hidden. Only the price and "Buy Now" button are displayed. Regular auction buyout lots still show the label.
- Removed increments table & terms links: On shop lot pages, the "Increments table" and "Terms and conditions" links are hidden since they don't apply to buy-it-now items. The "Make an inquiry" link remains.
Buyout confirmation modal overhaul
- Sales tax logic: The buyout confirmation modal now follows the same sales tax detection as the regular bid modal. When the auction house has a US state configured, displays "Sales Tax" instead of "VAT", with the correct percentage for same-state buyers and 0% for out-of-state.
- Hide 0% buyer's premium: The Buyer's Premium line is hidden when the commission is 0%.
- Shop-specific text: For shop buyouts, all disclaimer text is replaced with: *"You will receive an email with your invoice, including shipping, and a secure payment link."*
- Shop-specific buttons: "I don't Agree" → "Cancel", "I Agree" → "Buy". The "Terms of sale" button is removed for shop buyouts. Non-shop buyouts retain the original layout.
Purchase confirmed screen
- Title changed from "Confirm purchase:" to "Purchase Confirmed".
- Thank you message updated to: *"Thank you for your order. We will confirm your order within 1-2 business days and email you an invoice, including shipping, and a secure payment link."*
Share button settings (Appearance tab)
- Added a Share Buttons section to the BidSpirit Appearance settings tab with individual checkboxes for each sharing platform: Copy Link, WhatsApp, Facebook, Telegram, X (Twitter), VK, Pinterest, and Email.
- All platforms default to enabled (shown). Unchecking a platform hides that share button on all lot pages (both shop and regular auctions).
---
[3.7.0.7] — 2026-05-02
Identity stitch on bidder login — keyword interest tallying now actually fires
Why
The keyword extractor was filling
wp_af_stats_lot_keywordscorrectly (197 lots, 734 distinct keywords on Clumber), butwp_af_user_interestsandwp_af_user_recent_activitywere both empty — zero rows of any dimension. Same on every site running the new sync streams.Root cause: identity stitching (visitor_hash → email) only fired in the tracker AJAX when
is_user_logged_in()returned true. On these auction sites the actual bidders authenticate via BidSpirit, never aswp_users— so the WP login check was always false, the stitch table stayed empty, andmaybe_record_lot_view($url, $email, …)got called with an empty email and bailed out before tallying. Lot views by real bidders never landed in the user-side interest profile.What changed (no auth-path intervention)
The fix piggybacks on the *existing* fire-and-forget tracking AJAX that already runs after a successful BidSpirit login (
afLogIP("login", bidspiritUser)). It does not touch the BidSpirit auth path itself.inc/ip-logger.phpauctionforge_ajax_log_ip()— after the existingauctionforge_user_trackinginsert, if the request carries avisitor_hashand the email is valid, callsAF_Stats_Visitor_Email_Map::record($vh, $email, $ip). Wrapped in try/catch so any failure here can never break the existing tracking response.assets/js/app.js+src/js/app.jsafLogIP()— readslocalStorage['af_vid'](defensively, ITP/private-mode safe) and includes it asvisitor_hashin the POST body.inc/stats/class-stats-init.phpmaybe_record_lot_view()— when$emailis empty (the common case for BidSpirit-only bidders) but avisitor_hashis present, falls back toAF_Stats_Visitor_Email_Map::lookup($visitor_hash). If a stitch exists, the view tallies; if not, it stays anonymous.
Net effect: a bidder logs in (BidSpirit), the post-login tracker AJAX fires as it always has, and now also writes one extra row into
af_stats_visitor_emails. From that point onward, every page they view on the same browser/device tallies intoaf_user_interestskeyed on their email. The BidSpirit transaction itself is untouched.---
[3.7.0.6] — 2026-05-02
Critical fix —
X-API-Keyheader collision with sibling SmoothByte pluginsWhat was wrong
On any site running both AuctionForge and another SmoothByte-stack plugin that also points its updater at
wpdeploy.smoothbyteit.dev(e.g.seo-aeo-optimizer), the second plugin'shttp_request_argsfilter overwrote AuctionForge'sX-API-Keyheader on every outbound API call. Wpdeploy then 401'd because the key it received belonged to a different plugin instance — usually aseo_aeo_update_api_keythat wpdeploy had no record of.The symptom was a quiet, total auth failure:
report-health,check-updates, everysync-*route, all 401. The watchdog flagged streams as "gone" and updates stopped flowing. Affected sites: any install where the AuctionForge key and the sibling plugin's key happen to differ. Sites where both plugins shared a key were silently safe (the overwrite was a no-op).Fix
AuctionForge_Auto_Updater::add_download_auth()now refuses to clobber an existingX-API-Keyand, for download URLs, only stamps when the URL slug matches our own. That keeps targeted calls fromapi_request()intact regardless of filter ordering, and prevents either plugin from writing its key onto the other's download URL.The same fix has been applied to
seo-aeo-optimizerso both ends of the collision are defensive.---
[3.7.0.5] — 2026-05-02
Sync Status admin panel — diagnostic + manual triggers in wp-admin
Why
Diagnosing sync issues used to require shell access on the site or piecing together state from wpdeploy's app.log. This release surfaces the same diagnostics inside wp-admin so a site admin (or anyone with
manage_options) can see exactly what's happening and trigger fixes in one click.Lives inside the existing Sync Status menu (
Lots → Sync Status) — appended below the existing content as a "Sync Diagnostics & Manual Controls" section, no duplicate menu entry.What's on the panel
Connection summary — plugin version,
af_stats_db_version, wpdeploy server URL, last 8 chars of API key, keepalive install state + auto-reactivation count.Sync streams table — for each of the 10 cron hooks (user-tracking, user-profile, user-interests, user-activity, lots, bids+wins, vulnerabilities, report-health, check-updates, fraud-enforcement):
- Configured schedule
- Last fired timestamp + status colour-coded (green=success, blue=idle/empty, red=error)
- Record count from last run
- Next scheduled run
- Current watermark (where applicable)
- "Fire now" button — clears doing_cron, calls
do_action($hook)synchronously, shows the result
One-shot utilities
Test wpdeploy connection— calls/api.php/infowith the site's API keyClear stuck cron lock— deletes thedoing_crontransient (the classic fix when scheduled events stop firing)Reinstall keepalive— overwritesmu-plugins/auctionforge-keepalive.phpfrom the bundled templateBackfill bids from legacy tracking— replayslast_event_type='bid'rows fromwp_auctionforge_user_trackingintowp_af_bid_eventsso the bids-wins stream picks them up. Useful for sites that have years of bid history in the legacy table but nothing in the new queueRun all due events now— clears doing_cron and fires everyauctionforge_*cron event whose timestamp is past due, in one go
Live response output panel shows the JSON returned from each action so you can see what just happened without leaving the page.
Files Changed
- Created:
inc/admin/class-sync-status-page.php - Modified:
inc/stats/class-stats-init.php(load + init the panel) - Modified:
admin/view/sync-status.php(appendAF_Sync_Status_Page::render_panel()call at the bottom) - Modified:
auctionforge.php(Version 3.7.0.4 → 3.7.0.5)
Verification
Navigate to Lots → Sync Status in wp-admin on any 3.7.0.5 site. Scroll past the existing content to the new "Sync Diagnostics & Manual Controls" section. Click "Test wpdeploy connection" — you should see
{"success": true, "auth_type": "site"}. Click "Fire now" on any stream — the row's last-fired timestamp should refresh after 1–2 seconds.---
[3.7.0.4] — 2026-05-02
Self-healing: failed plugin updates can no longer take a site offline
Why
WordPress's plugin updater isn't transactional — when an update fails partway (corrupt unzip, fatal during the new version's
plugins_loaded, disk pressure, theme conflict, etc.) WP often deactivates the plugin and leaves the site without it. Once AuctionForge is dropped fromactive_plugins, no AF code runs again — including its sync handlers — until someone notices and reactivates manually. On the AuctionForge site fleet, this had quietly happened to ~5 sites we found; almost certainly more on production sites we don't have filesystem access to.This release ships an autonomous watchdog that lives outside the AuctionForge plugin entirely so it survives even when AF gets knocked out.
What changed
1. Self-installing keepalive (mu-plugin)
inc/keepalive/auctionforge-keepalive.template.php— a 50-line WordPress must-use plugin. Lives inwp-content/mu-plugins/, which WordPress can't deactivate. On everyplugins_loaded(priority 1, before any regular plugin), it checks: isauctionforge/auctionforge.phpon disk but missing fromactive_plugins? If yes AND the file has a validPlugin Name:header (smoke check — don't reactivate a corrupt zip), it re-adds AF andincludes the file in the same request.inc/keepalive/class-keepalive-installer.php— runs on every successful AF load. Copies the template intowp-content/mu-plugins/auctionforge-keepalive.phpif missing or version-bumped. Idempotent: comparesKEEPALIVE_VERSIONheaders, only writes on change. Refuses to overwrite a foreign mu-plugin (defensive against name collisions). Failure is non-fatal — install errors are recorded inwp_optionsfor wpdeploy visibility but never throw.
Net effect. Any site that successfully loads AF 3.7.0.4 or later will have the keepalive permanently installed in mu-plugins. From that point forward, even if a future update hard-fails, the keepalive recovers AF on the next pageview without any manual intervention or filesystem access. Crucially: this works on sites we don't own — the keepalive ships inside the AF zip, gets installed during the first successful update, and lives in mu-plugins thereafter.
2. Forensic markers
The keepalive writes three options on each recovery:
auctionforge_auto_reactivated_at— most recent recovery timestampauctionforge_auto_reactivated_count— total recoveriesauctionforge_auto_reactivated_failed_at— set when the keepalive saw AF on disk but with no Plugin Name header (genuinely corrupt — needs operator attention)
These get picked up by the AF sync streams and surfaced on the wpdeploy dashboard so you can see which sites have been quietly recovering themselves and whether a particular release is failing more than it should.
3. Companion: post-update-silence alerts on wpdeploy (server side)
Wpdeploy's
report-healthroute now compares incomingplugin_versionagainst the row and writeslast_version_changed_at+previous_plugin_versionon change. TheSyncWatchdogcron then alerts if a site has reported a version change but not sent any heartbeat for 2+ hours since — likely a failed install. Emitssync_incidentsrows withkind=post_update_failureso the existing Telegram fan-out picks them up. Each version-change event alerts at most once.Files Changed
- Created:
inc/keepalive/auctionforge-keepalive.template.php,inc/keepalive/class-keepalive-installer.php - Modified:
inc/stats/class-stats-init.php(callAF_Keepalive_Installer::maybe_install()on every plugin load) - Modified:
auctionforge.php(Version 3.7.0.3 → 3.7.0.4)
Companion server-side changes (already deployed on wpdeploy.smoothbyteit.dev — not in this zip):
sitestable:last_version_changed_at TIMESTAMP NULL,previous_plugin_version VARCHAR(20) NULLapi.php/report-health route detects version changesSyncWatchdog::maybe_alert_post_update_failure()emits the new alert kind
Verification
1. Drop a 3.7.0.4 install on any site. Confirm
wp-content/mu-plugins/auctionforge-keepalive.phpexists post-load.2. Manually deactivate AF from the database (
DELETE FROM wp_options ...active_plugins...). Hit the homepage. AF reappears inactive_plugins;auctionforge_auto_reactivated_countincrements.3. Delete
mu-plugins/auctionforge-keepalive.php. Trigger AF load (any pageview). The file reappears.4. Bump KEEPALIVE_VERSION in the source template, ship a new release, observe the installed mu-plugin update on next AF load.
Operator notes
- Sites currently in the broken state (AF deactivated, no keepalive yet) are NOT auto-rescued by this release — they need a one-time manual reactivation in wp-admin OR a fresh AF install via wp-admin's Upload Plugin. After that, the keepalive is in place and future failures self-heal.
- The post-update-failure alert won't fire for upgrades that happened before this release (no
last_version_changed_atwas recorded). It activates from the first version change wpdeploy sees from each site after this update lands.
---
[3.7.0.3] — 2026-05-02
Fix: profile re-sync on login / profile-edit / register (no more empty names)
Why
The hourly profile sync uses a
user_registeredwatermark — once a user has been pushed once, the watermark advances past them and they're never re-pulled. That meant:1. Existing users whose first_name/last_name became populated AFTER their first sync stayed empty on wpdeploy forever.
2. BidSpirit-driven sites that don't write WP's standard
first_name/last_namefields shipped empty rows even though the canonical name was visible indisplay_name.The People view was showing
—for the name on rows that absolutely had a name available — just not where the sync handler was looking.Fixes (
inc/sync/class-profile-sync.php+inc/stats/class-stats-init.php)AF_Profile_Sync::push_for_user_id($user_id, $blocking=false)— new public method that builds a single user's profile row, normalises it, and POSTs to wpdeploy bypassing the watermark. Non-blocking by default (wp_remote_postwithblocking=false, timeout=2s) so login latency is unaffected.build_user_row($user_id)extracted as a reusable helper. Both the hourly batch and the on-demand push call it. Centralises role-filtering + display_name fallback + usermeta probing.display_namefallback. Whenwp_usermeta.first_name/last_nameare both empty (typical on BidSpirit-only sites),build_user_row()parsesdisplay_name("John Smith" → first=John, last=Smith) so we don't ship a row with a blank name when the data is sitting on the user record itself.- Three new action hooks registered in
class-stats-init.php::init(): wp_login→push_for_user_id($user->ID)— every login refreshes the rowprofile_update→ same — profile edits in wp-admin refreshuser_register→ same — new registrations get pushed instantly (instead of waiting up to 60 min for the next cron tick)
Files Changed
- Modified:
inc/sync/class-profile-sync.php(refactor + new method + display_name fallback) - Modified:
inc/stats/class-stats-init.php(three new action hooks) - Modified:
auctionforge.php(Version 3.7.0.2 → 3.7.0.3)
Verification
1. On a 3.7.0.3 site, find a user whose
wpdeploy.user_profiles.first_nameis empty:SELECT site_id, email, first_name FROM user_profiles WHERE email='something@example.com'2. Log in as that user (or have them log in).
3. Within ~2 seconds, re-query —
first_nameshould now be populated, either from the standard meta key OR parsed fromdisplay_name.4. The non-blocking POST means the user's login experience is unchanged — no spinner, no extra latency.
Operator note
Existing wpdeploy rows with empty
first_name/last_namewill refresh automatically as users log in or edit their profile. To force a one-shot re-walk of every user on a site (regardless of watermark), reset the watermark there:DELETE FROM wp_options WHERE option_name='auctionforge_profile_sync_watermark';Next hourly cron will re-pull every non-admin user with the new fallback applied.
---
[3.7.0.2] — 2026-05-02
Fix: sync-lots datetime mismatch + idle syncs now heartbeat
Why
Two issues surfaced in the wpdeploy Sync Health dashboard:
1. Every site's
sync-lotswas stuck onapi_error. The plugin sendslast_modifiedstraight fromwp_bp_meta_data.lastUpdate, which is a Unix epoch string ("1756919754"). wpdeploy'slots.last_modifiedcolumn is aDATETIME, so MariaDB rejects the insert withSQLSTATE[22007]: Incorrect datetime value. The handler recordsapi_errorand the watermark never advances, so every cron tick re-fails on the same batch.2. Sites with nothing to sync looked dead. When a sync handler had an empty batch (e.g. no non-admin users yet) it was returning early without POSTing anything. wpdeploy's
update_sync_health()only fires on a successful POST, sosites.sync_health_jsonstayed NULL and the dashboard showed grey dots — indistinguishable from a broken cron. WP-Cron was actually firing fine; the watchdog just couldn't tell.Fixes
inc/sync/class-lots-sync.php— newepoch_to_datetime()helper converts the BidSpirit epoch field to UTCY-m-d H:i:sbefore shipping. Idempotent: already-formatted datetimes pass through untouched, invalid values becomeNULL.inc/sync/class-sync-base.php::run()— always POST, even when the batch is empty. Empty payload is{records: []}and wpdeploy's existing handlers handle it gracefully (loop is skipped,update_sync_health()still fires withsynced=0). This makes the dashboard reflect cron liveness, not just data flow.
Files Changed
- Modified:
inc/sync/class-lots-sync.php - Modified:
inc/sync/class-sync-base.php - Modified:
auctionforge.php(Version 3.7.0.1 → 3.7.0.2)
Verification
1. On Clumber:
do_action('auctionforge_sync_lots')— confirm the previousauctionforge_last_sync-lots_status = api_errorflips tosuccess(N)and thatwpdeploy.lotsnow contains rows.2. On a site with no non-admin users:
do_action('auctionforge_sync_user_profile')— confirmauctionforge_last_sync-user-profile_status = idle(0)AND that wpdeploy's Sync Health page now shows a green dot for that cell.---
[3.7.0.1] — 2026-05-02
Fix: marketing data leaks WordPress admins into the people list
Why
After the 3.7.0.0 rollout the central
peopleview on wpdeploy was showing site administrators alongside real auction-house users — thesync-user-profilehandler read straight fromwp_userswith no role filter, so any account with administrator/editor/author/contributor/shop_manager capabilities was getting shipped as if it were a buyer. Marketing audiences must contain buyers, not staff.Fixes (
inc/sync/class-profile-sync.php)- The
read_batch()SQL now LEFT JOINs{$wpdb->usermeta}on the prefix-aware capabilities key ({$wpdb->prefix}capabilities) and filters out any user whose serialized capabilities meta_value containsadministrator,editor,author,contributor,shop_manager, orsuper_admin. Users withIS NULL(no roles registered) are still allowed through — those are typically subscribers/buyers on this fleet. - Watermark on
auctionforge_profile_sync_watermarkis unchanged; the next run after upgrade picks up the same batch with the new filter applied. Operationally the wpdeploy team also wiped the existing admin rows fromuser_profiles,user_interests,user_recent_activity,bids_wins, andpeopleto clear the leak server-side — total of 35 rows scrubbed.
Files Changed
- Modified:
inc/sync/class-profile-sync.php - Modified:
auctionforge.php(Version 3.7.0.0 → 3.7.0.1)
Verification on Clumber dev
1. Find a logged-in admin:
SELECT u.user_email FROM wp_users u JOIN wp_usermeta um ON um.user_id=u.ID AND um.meta_key='wp_capabilities' WHERE um.meta_value LIKE '%administrator%';2. Reset the watermark:
DELETE FROM wp_options WHERE option_name='auctionforge_profile_sync_watermark';3. Trigger sync:
do_action('auctionforge_sync_user_profile');4. On wpdeploy: confirm those admin emails do NOT appear in
user_profiles(SELECT * FROM user_profiles WHERE email='admin@…';returns zero rows).Privacy / scope
- No API contract changes. The wpdeploy
/api.php/sync-user-profileroute accepts the same payload shape; this is purely a source-side filter narrowing what gets sent.
---
[3.7.0.0] — 2026-05-02
Cross-site user data lake — full Phase 2 + Phase 3 build
Why
AuctionForge sites were exposing per-lot engagement (views, favourites, bids, wins) keyed only on the anonymous
af_vidlocalStorage hash, with no central aggregation. Marketing — even the "collect data now, send later" phase — needs a per-person view across the whole AF network: name + phone + postcode + country + IP + device fingerprint + the keywords they engage with + the bids they place + the lots they win, all rolled up across every site they've used. This release wires every piece needed for that, and keeps it sustainable: per-site aggregates rather than raw event firehose, watermarked syncs with retry, 14/30-day site-side retention, watchdog + Telegram alerts for dead streams.See
/root/.claude/plans/i-want-to-add-synthetic-goose.mdfor the full architecture.New tables (idempotent dbDelta on the existing
plugins_loadedmigration path)wp_af_stats_lot_keywords— per-lot keyword cache. Title + tags + author tokenized (lowercase → drop stop-words → drop ≤2-char → drop pure-digit), one row per (post_id, keyword). Populated onsave_post_lot.wp_af_user_interests— running tally per(user_email, dimension, dimension_value)where dimension ∈keyword | category | author | price_band. UPSERT-keyed so increments are atomic. Bounded by users × distinct interests (typically a few dozen rows per user).wp_af_user_recent_activity— capped per-user activity log (last 50 events per email). Seeds the drill-down timeline on the wpdeploy person view.wp_af_bid_events— bid + win events (auto-created by the bids sync handler). Drained and shipped to wpdeploy hourly.synced_atcolumns added towp_af_stats_pageviews,wp_af_stats_sessions,wp_af_stats_searches,wp_af_stats_outbound. Powers the durable sync-and-purge lifecycle.af_stats_db_versionbumped 2 → 3. The existingAF_Stats_Init::maybe_create_tables()picks up the new tables on the next admin page load after auto-update.
New helper classes
AF_Keyword_Extractor(inc/stats/class-keyword-extractor.php) — pure tokenizer + cache writer + read-through helper. Hookssave_post_lotto refresh on lot changes. Stop-words tunable viaapply_filters('af_keyword_stop_words', ...).AF_User_Interests(inc/stats/class-user-interests.php) —record_view / record_favorite / record_bid / record_win. All idempotent UPSERTs. CallsAF_Stats_Tracker::should_skip()first so admins/bots never pollute interest profiles.AF_Sync_Base(inc/sync/class-sync-base.php) — abstract durability backbone. Readssynced_at IS NULLbatches, POSTs, marks rows synced only on a confirmed 200, retries on next cron run if the POST fails. Idempotent UNIQUE keys on the wpdeploy side mean retries never duplicate.AF_Profile_Sync/AF_Interests_Sync/AF_Activity_Sync/AF_Lots_Sync/AF_Bids_Sync— five concrete sync streams.AF_Data_Purge(inc/maintenance/class-data-purge.php) — daily cron: 14-day floor on synced rows, 30-day hard cap with CRITICAL alert if any unsynced row hits the cap (which would mean wpdeploy has been unreachable for a month).
New cron schedules (auto-registered on plugins_loaded if
auctionforge_update_server_url+_api_keyare configured)| Hook | Schedule | Endpoint |
|---|---|---|
|
auctionforge_sync_user_profile| hourly |POST /api.php/sync-user-profile||
auctionforge_sync_user_interests| hourly |POST /api.php/sync-user-interests||
auctionforge_sync_user_activity| hourly |POST /api.php/sync-user-activity||
auctionforge_sync_lots| every 10 min |POST /api.php/sync-lots||
auctionforge_sync_bids_wins| hourly |POST /api.php/sync-bids-wins||
auctionforge_purge_synced_data| daily | (purge cron — local) |All sync handlers are watermarked or
synced_at-gated; cron mid-run failure is harmless because the next run picks up the same rows.Hooks fired
af_stats_pageview_recorded($url, $email, $visitor_hash)— fires insideAF_Stats_Ajax::handle_track()after a logged-in pageview is recorded. Default listener resolves URL → lot post →AF_User_Interests::record_view().af_stats_lot_favorited($email, $post_id)— fires from the existinglot_analytics_record_favoriteAJAX handler when a watchlist add happens. Default listener callsrecord_favorite().
Server-side companion (wpdeploy)
This release is paired with wpdeploy changes (handled out-of-band; not in the plugin zip):
- 5 new API routes matching the sync streams above. All return
synced+ watermark metadata so the plugin can advance / mark rows synced. update_sync_health()helper in wpdeploy — every successful sync POST writes(stream, last_seen_at, last_synced_count, state)intosites.sync_health_json.SyncWatchdog— 5-minute cron on wpdeploy that scans every (site × stream) cell and runs anok → overdue → gone → recovering → okstate machine. Emits alerts via the existingsync_incidentsTelegram fan-out.- People section in the wpdeploy admin —
?tab=people(cross-site rollup with top keywords / lifetime spend),?tab=person&email=...(drill-down with timeline + bids),?tab=people-export(Google Customer Match + Meta Custom Audience CSV with sha256 hashing per spec). ?tab=sync-health— site × stream traffic-light grid showing every sync's state.
Files Changed
- Created:
inc/stats/class-keyword-extractor.php,inc/stats/class-user-interests.php,inc/stats/stop-words.php - Created:
inc/sync/class-sync-base.php,inc/sync/class-profile-sync.php,inc/sync/class-interests-sync.php,inc/sync/class-activity-sync.php,inc/sync/class-lots-sync.php,inc/sync/class-bids-sync.php - Created:
inc/maintenance/class-data-purge.php - Modified:
inc/stats/class-stats-database.php(DB_VERSION = 3, new dbDelta calls, synced_at column adds) - Modified:
inc/stats/class-stats-init.php(require new classes, register sync crons, wireaf_stats_pageview_recordedandaf_stats_lot_favoritedlisteners) - Modified:
inc/stats/class-stats-ajax.php(fireaf_stats_pageview_recordedafter pageview record; fireaf_stats_lot_favoritedon watchlist add) - Modified:
auctionforge.php(Version: 3.6.4.0 → 3.7.0.0)
Verification on Clumber dev
1. After auto-update + first wp-admin page load:
wp_af_stats_lot_keywords,wp_af_user_interests,wp_af_user_recent_activityall exist;af_stats_db_version = 3.2. Save a test lot titled
"Pair of Victorian silver candlesticks by Mappin & Webb"→wp_af_stats_lot_keywordshas rows forvictorian, silver, candlesticks, mappin, webb(and notpair, of, by).3. Log in as throwaway test user, view 3 of those lots →
wp_af_user_interestsshows(test@…, keyword, 'victorian', view_count=3).4. Wait one hourly cron, confirm
wpdeploy.user_interestsmirror via the wpdeploy admin →?tab=people→ search for the test email.5. Confirm
wpdeploy.sites.sync_health_jsonhasuser-interests.state = 'ok'for the Clumber site.6. Pause the cron, wait 2h, watch the watchdog flip the cell to
overdueand emit a Telegram alert.Privacy / scope
- Admins and bots are filtered out at write time via
AF_Stats_Tracker::should_skip(). - Email is normalized lowercase + trim before storage; phone normalized to E.164 (UK-aware) on the sync side.
- No outbound activation yet — wpdeploy stores everything but doesn't send anything to anyone. Marketing send mechanics (consent flag, suppression list, sender) explicitly deferred.
---
[3.6.4.0] — 2026-05-02
Identity stitching: visitor_hash → user_email
Why
The
af_stats_*tables (pageviews,sessions,searches,outbound) and the lot-engagement tables (af_lot_analytics,af_lot_shares) currently store activity keyed only on the anonymousaf_vidlocalStorage hash — there is no link from any browsing event to the user's email even when they're logged in. Without that link, the central wpdeploy server can never aggregate behavioural data on a per-person basis, which is the prerequisite for the cross-site user-data lake being built on wpdeploy (see/root/.claude/plans/i-want-to-add-synthetic-goose.mdPhase 1).This release adds the bridge: every authenticated tracker hit records a
(visitor_hash, user_email)pair into a new table. From here on, anonymous browsing can be resolved to an email via JOIN for any session the user was logged in.Changes
- New table
wp_af_stats_visitor_emails—(visitor_hash, user_email, ip_address, first_seen, last_seen)withUNIQUE(visitor_hash, user_email)+ index onuser_email. Created viadbDeltainside the existingAF_Stats_Database::create_tables()so it ships through the standardplugins_loadedmigration path — no manual reactivation needed after auto-update. af_stats_db_versionbumped 1 → 2.AF_Stats_Init::maybe_create_tables()now compares against the newAF_Stats_Database::DB_VERSIONconstant rather than a hard-coded< 1, so future schema bumps (Phase 2 onwards) just require constant edits + new dbDelta calls.- Identity record on every authenticated tracker hit.
AF_Stats_Ajax::handle_track()now callsAF_Stats_Visitor_Email_Map::record($visitor_hash, $email, $ip)wheneveris_user_logged_in()is true. Trust boundary: the email is read server-side fromwp_get_current_user()— clients cannot assert who they are. - Defensive table-exists guard. The new helper short-circuits silently if the migration hasn't run yet on a given site (race window on the very first request after auto-update); the next request finds the table and proceeds. No fatals, no missing rows.
- Email normalised at write time — lowercase + trim +
is_email()validation before storage. Marketing audience match-rates downstream depend on consistent casing.
Files Changed
- Created:
inc/stats/class-visitor-email-map.php - Modified:
inc/stats/class-stats-database.php(DB_VERSION constant; new table; drop_tables list) - Modified:
inc/stats/class-stats-init.php(require new helper; migration check uses constant) - Modified:
inc/stats/class-stats-ajax.php(record pair inhandle_track) - Modified:
auctionforge.php(Version header bump)
Verification on Clumber dev
1. After auto-update, load any
wp-admin/*page once →wp_af_stats_visitor_emailsexists,af_stats_db_version = 2.2. Log in as a test user, browse 5 lots → exactly one row in
wp_af_stats_visitor_emailsfor that(visitor_hash, email)pair, withlast_seenupdating on each hit.3.
SELECT email FROM wp_af_stats_visitor_emails WHERE visitor_hash IN (SELECT visitor_hash FROM wp_af_stats_pageviews WHERE created_at > NOW() - INTERVAL 1 HOUR)returns the test email — proving the JOIN works.Privacy / scope
- This change writes a
(visitor_hash, email)pair to a single new table on the AF site. Nothing is sent to wpdeploy yet — the sync stream lands in Phase 2. - Anonymous (logged-out) browsing is unaffected: no row is created until the user authenticates.
- Bots are still skipped via
AF_Stats_Tracker::is_bot()before any tracking writes.
---
[3.6.3.1] — 2026-05-01
Fix: New lots never processed + Live console improvements
Why
When BidSpirit adds new lots to an auction (e.g. items 683-692), the sync pipeline correctly staged all 709 lots into
import_historybut the InsertLotsBS processing loop exited after the first batch of 500 unchanged lots, never reaching the genuinely new lots at the tail of the queue. This caused new lots to remain permanently stuck in staging — synced but never created as WordPress posts.Separately, the admin Live Console was replaying the entire log history from the beginning on every page load, and showed long silent gaps during API calls with no indication of what the worker was doing.
Fixes
- InsertLotsBS loop break condition — The stage 5 insert loop in
CatalogSyncWorker::process()andprocessDayEnded()previously broke whenupdated lots === 0, even if the batch had cleared hundreds of unchanged ("unupdated") lots from the queue. New lots with higher IDs were never reached. Now breaks only when bothupdated lotsandunupdated lotsare 0, meaning the staging queue is truly empty. - Live Console starts from current position —
consoleSinceIdwas hardcoded to0, causing the console to page through the entireaf_sync_logtable (50 rows at a time) before reaching real-time entries. Now initializes toSyncLogger::getLatestId()so only entries created after page load appear. queueIsActivedeclaration order — Variable was declared after functions that referenced it, causing the console to always start at the slow 3s polling rate even when a worker was active. Moved declaration before first use.- Progress logging during API calls —
LotList::auctionProcessing()made 2-3 BidSpirit API calls with zeroSyncLoggerentries, creating long silent gaps in the console. Added log entries for API fetch start, response received (with duration), data staged, and API errors. - Per-auction progress in bulk runs —
LotList::run()now logsProcessing auction X/Y: {id}for each auction in the bulk loop, and logs skipped auctions. processDayEndedinsert loop logging — Added batch progress logging and timeout guard matching theprocess()method pattern. Previously this loop was completely silent.
Files Changed
- Modified:
inc/sync/CatalogSyncWorker.php,inc/import/LotList.php,admin/view/sync-status.php
---
[3.6.3.0] — 2026-05-01
Public Auctions API — Token Authentication
Why
The
/wp-json/auctionforge/v1/public/auctionsendpoint added in v3.6.2.9 was publicly accessible. Since auction data should only be served to authorized aggregator sites, the endpoint now requires a valid auth token.Changes
- Token verification — The
PublicAuctionsREST endpoint now validates anX-AF-Tokenheader (or?token=query parameter) against the site's existing Webhook auth token from AuctionForge settings. - Returns
401 Unauthorizedfor missing/invalid tokens and403 Forbiddenif no auth token is configured on the site. - Uses
hash_equals()for timing-safe comparison.
Files Changed
- Modified:
auctionforge.php,inc/api/PublicAuctions.php
---
[3.6.2.9] — 2026-05-01
Public Auctions REST API Endpoint
Features
- New REST endpoint
GET /wp-json/auctionforge/v1/public/auctions— Exposes auction list data (title, date, image, state, catalog link) for consumption by the AuctionForge Hub plugin on parent/main sites. - Parameters:
type(upcoming or past, default: upcoming),limit(max results, default: 50). - Handles multi-day auctions with correct part numbers and catalog links.
- Returns auction metadata including
auction_id,source_site, andday_indexfor deduplication.
Files Changed
- Modified:
auctionforge.php,inc/coreIncludes.php - Created:
inc/api/PublicAuctions.php
---
[3.6.2.8] — 2026-04-30
Suppress alerts for transient retry conditions
Why
The "BidSpirit API returned 0 lots — catalog may not be ready yet" message is logged when the BidSpirit webhook fires before the auction catalog is fully published. The safety cron retries the job automatically and it usually succeeds on the next attempt — there's no operator action required, so a Telegram alert is just noise.
Fix
- New private helper
SyncLogger::isSuppressedFromAlerts($message, $context)matches the message against a substring allowlist of known-transient errors. When matched, the row is still inserted intoaf_sync_log(so the in-app sync console still shows the retry chain) but theauctionforge_sync_error_loggedfan-out action does NOT fire — wpdeploy and Telegram stay quiet. - Default suppression substrings:
"BidSpirit API returned 0 lots","catalog may not be ready yet". - Extendable via the new
auctionforge_sync_alert_suppress_patternsfilter — themes/MU plugins can add their own substrings.
Files Changed
- Modified:
auctionforge.php,inc/sync/SyncLogger.php
---
[3.6.2.7] — 2026-04-30
Typo fix
- Settings → Connections tab: the placeholder/help text under the Server field showed
https://my-accaunt.bidspirit.com/(extra "a"). Now readshttps://my-account.bidspirit.com/.
Files Changed
- Modified:
auctionforge.php,inc/controllers/Settings.php
---
[3.6.2.6] — 2026-04-30
Fix stale
plugin_versionin reportsWhy
Sites were reporting their old version to wpdeploy long after they'd been upgraded — e.g. Lonsdale Auctioneers ran v3.6.1.1 but kept telling wpdeploy it was on v2.9.6. Root cause: the constant
AUCTIONFORGE_VERSIONis read from the plugin file'sVersion:header *once at plugin load*, then frozen into$this->current_versionon the auto-updater instance. After a plugin upgrade replaces the file on disk, existing PHP-FPM workers keep using the cached constant value until they're recycled, so every report from those workers carries the old version.Fix
- New helper
AuctionForge_Auto_Updater::get_live_version()reads the version directly from the plugin file's header on each call (viaget_file_data()— uncached). report_health,push_sync_error_immediate, andretry_sync_errorsnow sendget_live_version()instead of the cached constant.- The pre-existing iteration through active plugins inside
report_healthalready usedget_plugin_data()per plugin, so secondary plugin entries were already accurate; only the top-levelplugin_versionfield was stale.
Files Changed
- Modified:
auctionforge.php,inc/class-auto-updater.php
---
[3.6.2.5] — 2026-04-30
Real diagnostics for plugin self-updates
Why
The wpdeploy
update_queuetable had a 46% historical failure rate, but every single failure row stored the literal string"Installation failed"— collapsing every failure mode into one opaque error with no diagnostic value. Root cause: theinstall_update()method in both clients (AF auto-updater and wpd-client) treatedPlugin_Upgrader::upgrade()as a boolean, throwing awayWP_Errorobjects and skin-emitted error messages.Fixes (
inc/class-auto-updater.phpinstall_update())- Refreshes the
update_pluginstransient before invoking the upgrader. The upgrader reads from this transient to know what version to download; if WP hasn't checked recently, the upgrader silently returns false (looking like a failure even though there's a real update queued at wpdeploy). - Distinguishes
WP_Error,false/null, and success.WP_Errorwas previously treated as truthy → reported as "completed" even on failure. Now extracts the error code and message. - Reads
Automatic_Upgrader_Skin::get_errors()to surface the real upgrader-emitted error messages. - Reads
$upgrader->resultwhich holds the finalWP_Errorfor some failure paths. - Captures PHP errors/warnings emitted during the upgrade (file-move issues, etc.) via a temporary
set_error_handler. - Detects "no update in transient" as a distinct failure cause and labels it explicitly so we know it's a transient-cache problem, not an actual install failure.
- Truncates the combined diagnostic to 1000 chars before sending.
The same fix is applied to
wpd-client.php(the WPD client plugin shipped fromclient-plugin/wpd-client.phpon the wpdeploy server).Files Changed
- Modified:
auctionforge.php,inc/class-auto-updater.php
---
[3.6.2.4] — 2026-04-30
Bulk-sync worker dispatch fix
Fixes
- The HTTP-loopback worker (
auctionforge_rest_sync_workerinauctionforge.php) had its own switch statement for job-type dispatch, distinct from the one incrontasks/syncWorker.php. The newfull_sync_upcomingandfull_sync_pastjob types were only added to the CLI worker, so the loopback path produced "Unknown job type" errors. Both switches now route those types toBulkSyncWorker::process. inc/coreIncludes.phpnowrequire_oncesBulkSyncWorker.phpso the class is available wherever sync code runs.
Files Changed
- Modified:
auctionforge.php,inc/coreIncludes.php
---
[3.6.2.3] — 2026-04-30
Fixes for end-to-end Telegram round-trip
Fixes
verify_api_keyreads the option fresh on every call (hash_equalsagainstget_option('auctionforge_update_api_key')) instead of relying on the cached$this->api_keyfrom constructor time. Different FPM workers can hold different cached values when the option drifts (e.g. via auto-heal collisions), which previously produced intermittent 401s on REST endpoints.- New REST endpoint
POST /wp-json/auctionforge/v1/sync/version— wraps the existingtrigger-installflow with a JSON response (always HTTP 200 withsuccessflag). The original endpoint returnedWP_Error('no_update', …, status: 404)when the plugin was already on the latest version, which nginx'serror_page 404directive then clobbered with a static HTML 404 page on hosts using aaPanel/BTWAF. Keeping the URL under/sync/*matches the pattern that's already proven to pass through host WAFs.
Files Changed
- Modified:
auctionforge.php,inc/class-auto-updater.php
---
[3.6.2.2] — 2026-04-29
Catalog-sync kind disambiguation
Fix
catalog_syncjobs target a single auction that may be either active or archived. Until now their alerts were always classified askind=upcoming. The classifier now resolves the auction'sauction_stateterm meta and routes:ARCHIVED/ENDED/POST_AUCTION→kind=past→ Kill + Full Past buttons- anything else (or unresolvable) →
kind=upcoming→ Kill + Full Upcoming buttons
Files Changed
- Modified:
auctionforge.php,inc/class-auto-updater.php
---
[3.6.2.1] — 2026-04-29
Telegram Sync Monitoring follow-ups
Features
- Context-aware alert buttons. Each Telegram alert now shows the action set most relevant to the failing sync: upcoming-sync errors get Kill + Full Upcoming, past-sync errors get Kill + Full Past, everything else gets Kill only. Button choice is driven by a new
kindfield classified at log-write time from the queue'sjob_type. - Plugin version in alerts + Update button. Each push now includes the live
plugin_version. wpdeploy compares it to the latestis_stable=1row in itsversionstable and only renders an Update plugin button when the site is behind. Tapping Update calls the existingPOST /wp-json/auctionforge/v1/trigger-installendpoint to force the upgrade.
Architecture
- New private helper
AuctionForge_Auto_Updater::classify_error_kind($jobId)looks up the job'sjob_typeand maps it to'upcoming'/'past'/'other'. Used by both the immediate push and the 1-min retry cron. - Outbound payloads now include
plugin_versionat the top level; wpdeploy refreshessites.plugin_versionon every/sync-errorsPOST.
Files Changed
- Modified:
auctionforge.php,inc/class-auto-updater.php
---
[3.6.2.0] — 2026-04-29
Telegram Sync Monitoring & Remote Control
Features
- Instant Telegram alerts on sync errors. Any
level='error'row written toaf_sync_logis pushed (fire-and-forget, non-blocking) to wpdeploy, which fans it out to a configured Telegram group with inline-keyboard action buttons (Kill / Full Upcoming / Full Past / Acknowledge). - Remote command surface. Any group admin can tap a button to:
- Kill sync — flips DB flags via
SyncQueue::cancelAll(), then SIGTERMs every active worker; a 5-second watchdog escalates to SIGKILL for any survivor. - Full sync upcoming — full re-import of every active auction and its lots (queued, observable, killable). Replaces the
re-sync?do=importBidSpiritUpcomingflow with a queued equivalent. - Full sync past — same, for archived auctions.
- Safety-net retry cron (
auctionforge_retry_sync_errors, every minute) re-pushes recent error rows. wpdeploy dedupes viaUNIQUE(site_id, af_log_id)so duplicates are silent.
Architecture
SyncLogger::log()now firesdo_action('auctionforge_sync_error_logged', …)onlevel='error'so any handler can react. The auto-updater listener does a 2 s non-blocking POST to/api.php/sync-errors.- New REST endpoint
POST /wp-json/auctionforge/v1/sync/cancel-all(X-API-Key auth) — runsSyncQueue::cancelAll()+ SIGTERM + watchdog. Logs every action throughSyncLogger. POST /sync/startextended with amodeparameter (upcomingdefault,pastfor archived). Bulk re-sync is now a queued job, not a synchronous block.- New job types
full_sync_upcomingandfull_sync_pastonSyncQueue, dispatched to a newBulkSyncWorkerthat wraps the existingAuctionList::init()+LotList::init($upcoming)pipeline. syncWorker.phpinstalls a SIGTERM handler that flips the in-flight job tofailedwith a "Killed by admin (SIGTERM, cleanup OK)" marker and closes the DB cleanly before exiting. Watchdog escalates to SIGKILL after 5 s grace.LotList::auctionProcessing()now heartbeats the active bulk-sync job between auctions, preventing the safety cron from auto-failing long bulk runs as stale (the 600 s threshold is unchanged).
Files Changed
- Modified:
auctionforge.php,inc/sync/SyncLogger.php,inc/sync/SyncQueue.php,inc/class-auto-updater.php,crontasks/syncWorker.php,inc/import/LotList.php - Created:
inc/sync/BulkSyncWorker.php
---
[3.6.1.6] — 2026-04-29
High-Value Lot Modes for
[bp_lot_list]Features
high_value_pastmode — Displays past auction lots ordered by their catalog estimate (estimatedPriceInt), highest first. Useful for "Top Lots" or "Highlights" sections.high_value_soldmode — Displays past sold lots ordered by their actual sold price (soldBid), highest first. Only includes genuinely sold lots (soldBid > 0) and reuses the same false-positive guard asrandom_pastto skip lots wheresoldBidwas carried over fromstartPricewithout real bidding activity.- Admin documentation updated — The Shortcodes reference page in WP Admin now lists both new modes in the
modeattribute description and includes example shortcode usage.
Architecture
- New constants
MODE_HIGH_VALUE_PASTandMODE_HIGH_VALUE_SOLDonLotsWidget. - New method
LotsWidget::getLotListHighValue($mode, $limit)builds the query, applies the past-auction tax filter, setsbp_orderbyto the relevant meta field withDESCorder, and (for the sold variant) filters out unsold-but-stale lots in PHP. - New filter hook
bp_lot_list_high_value_args_filterfor downstream customization of the WP_Query args.
Files Changed
- Modified:
inc/widgets/LotsWidget.php,inc/controllers/ShortcodesPage.php
---
[3.6.0.18] — 2026-04-25
Brevo SMS Notifications Integration
Features
- Transactional SMS via Brevo API — The plugin now sends text message alerts through the Brevo transactional SMS service, running alongside existing Firebase push notifications.
- Four Notification Types:
- New Auction Published — Broadcast SMS to all opted-in subscribers when an auction is published.
- Auction Starting Soon — Targeted SMS to users registered for an auction when it is about to start.
- Favorited Item Live Soon — Targeted SMS to users who favorited a lot when it is approaching in the auction.
- Outbid Notice — SMS sent when a user's leading bid is surpassed, with a 5-minute per-item cooldown to prevent spam.
- SMS Subscriber Database — New
af_sms_subscriberstable stores user phone numbers, country codes, and per-notification-type opt-in preferences (GDPR-ready explicit consent). - Admin Settings Tab — New "SMS Notifications" tab in Settings with:
- Brevo API Key input
- SMS Sender Name (11 char max)
- Master enable/disable toggle
- Per-notification-type on/off switches
- Test SMS widget with phone input and send button
- Live subscriber count display
- Profile SMS Preferences — Users can opt into SMS notifications directly from their profile page with phone number entry and granular notification type selection.
Architecture
- BrevoSMS Service (
inc/services/BrevoSMS.php) — cURL-based API wrapper with broadcast, targeted, and single-send methods, message builders with 160-char limit awareness, rate limiting, and comprehensive error logging. - SMSSubscriber Model (
inc/model/SMSSubscriber.php) — CRUD operations, email-to-phone resolution, opt-in filtering, and upsert logic. - Webhook Integration — SMS dispatch hooks added to
AuctionsAPI.phpmethods:leading_bid_surpassed(),item_live_soon(),auction_starts_soon(), andauctionPublishedPush().
AJAX Handlers
auctionforge_sms_save— Save SMS preferences from profile pageauctionforge_sms_load— Load SMS preferences for profile pageauctionforge_sms_test— Admin-only test SMS endpoint
Database
- New table:
af_sms_subscribers— Phone numbers, country codes, per-notification opt-ins, timestamps
Files Changed
- Modified:
auctionforge.php,inc/coreIncludes.php,inc/controllers/AuctionsAPI.php,inc/controllers/Settings.php,admin/view/settings.php,templates/parts/profile-templates.php - Created:
inc/services/BrevoSMS.php,inc/model/SMSSubscriber.php
---
[3.6.0.7] — 2026-04-14
Hotfix
Fixes
- Namespace resolution — Fixed fatal error in
wp_footercommission label hook caused by unqualifiedSettingsHelperandSettingsclass references. Now uses fully qualified namespaces.
Files Changed
- Modified:
auctionforge.php
---
[3.6.0.6] — 2026-04-14
Commission Label Override Fix
Fixes
- Theme template override compatibility — Moved the commission label JS override from the
single-lot.phptemplate intoauctionforge.phpviawp_footerhook (priority 99). Sites with theme-level template overrides (e.g.themes/*/auctionforge/single-lot.php) were not picking up the inline script. Thewp_footerapproach works universally on all single lot pages.
Files Changed
- Modified:
auctionforge.php,templates/single-lot.php
---
[3.6.0.5] — 2026-04-14
Commission Label Override
Features
- Commission Label Setting — New dropdown in Settings → Appearance allowing admins to choose between "Buyer's Premium" (default) and "Auction House Commission" as the label displayed on lot pages. This overrides the Bidspirit JS client's default label using a MutationObserver that catches asynchronously injected text.
Files Changed
- Modified:
inc/controllers/Settings.php,templates/single-lot.php
---
[3.6.0.4] — 2026-04-12
Auction Approval Modal Redesign
Changes
- Removed BidSpirit Terms of Use — The generic BidSpirit "Terms of Use" section that appeared at the top of the non-credit-card approval modal has been removed. The modal now shows only the auction house's own legal agreements managed within the plugin.
- Renamed Modal Title — Changed "Terms of conditions" to "Terms & Conditions".
- Larger Scroll Area — The Terms & Conditions scroll box is now 350px tall (up from 200px) for easier reading.
- Proportional Section Heights — Refund & Return Policy and Chargeback Waiver sections use a shorter 260px scroll box to visually distinguish them from the primary Terms & Conditions.
Files Changed
- Modified:
templates/js-chunks/approval-info.php,assets/js/app.js
---
[3.6.0.2] — 2026-04-10
Webhook Token Generator
Features
- Token Generator Widget — Added a 16-character random token generator directly below the "Webhook auth token" field on the Settings page. Includes a "Generate Token" button and a clipboard copy icon with visual feedback.
Files Changed
- Modified:
inc/controllers/Settings.php
---
[3.6.0.1] — 2026-04-10
Patch
Changes
- Version bump.
---
[3.6.0.0] — 2026-04-10
Legal Agreements for Auction Approval
Features
- Terms & Conditions — A mandatory, scrollable Terms & Conditions document is now displayed during the auction approval process. Bidders must scroll to the bottom and check an agreement box before their approval request is submitted. Always enabled.
- Refund & Return Policy — An optional, scrollable Refund & Return Policy can be enabled in Settings. When enabled, bidders must read and accept it during auction approval.
- Chargeback Waiver — An optional, scrollable Chargeback Waiver can be enabled in Settings. When enabled, bidders must read and accept it during auction approval.
- Admin Management — New "Legal Agreements" page under the Bidspirit admin menu with tabbed TinyMCE editors for each agreement type. Includes automatic version numbering (incremented on content change) and full version history.
- Consent Logging — Every agreement acceptance is logged to a dedicated database table (
af_user_agreement_log) with the agreement type, version, user email, IP address, user agent, auction ID, and timestamp. - User Tracking Integration — Agreement events (
terms_agreement,refund_agreement,chargeback_waiver) are also recorded in the existing IP tracking system alongside registration, login, and bid events. - Placeholder Content — Default sample content is seeded on plugin activation for all three agreement types.
Settings Added
- Enable Refund & Return Policy — Toggle to require bidders to accept the refund policy during auction approval.
- Enable Chargeback Waiver — Toggle to require bidders to accept the chargeback waiver during auction approval.
Database
- New table:
af_legal_agreements— Current active agreement content per type - New table:
af_legal_agreement_versions— Version history archive - New table:
af_user_agreement_log— User consent records
Files Changed
- Modified:
auctionforge.php,inc/controllers/Settings.php,inc/controllers/BidspiritViews.php,inc/ip-logger.php,templates/js-chunks/approval-info.php,assets/js/app.js - Created:
inc/legal/class-legal-agreements.php,admin/view/legal-agreements.php
---
[3.5.0.6] — 2026-04-08
Bid Event Tracking
Features
- Bid Tracking — All successful bids (regular, catalog, pre-sale buyout, post-sale purchase) now fire
afLogIP("bid", bidspiritUser)to capture the bidder's full identity in the user tracking table. - Whitelist Update — Added
bidto the allowedevent_typevalues in both the local plugin and the central WPDeploy API.
---
[3.5.0.5] — 2026-04-08
Self-Healing Database Schema
Features
- Auto-Migration — The plugin now auto-detects and adds any missing tracking table columns on version upgrade, ensuring sites with older schemas seamlessly migrate without manual SQL.
---
[3.5.0.4] — 2026-04-08
API Key Auto-Healing
Features
- Seamless Self-Registration — The WordPress plugin now autonomously regenerates and saves a fresh API Key whenever WPDeploy rejects a payload with an
api_key_collisionerror. This guarantees zero-downtime security handovers when developers clone instances to proxy/staging servers.
---
[3.5.0.3] — 2026-04-08
API Key Collision Defense
Features
- 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_collisionerrors, directly instructing developers to update cloned keys.
---
[3.5.0.2] — 2026-04-08
Modal Trigger Hotfix
Fixes
- Restructured internal UI rendering priority to gracefully deploy the inline Modal triggers inside custom IP log view without colliding with cached
z-indexstacks.
---
[3.5.0.1] — 2026-04-08
Hotfix
Fixes
- Timed Auction Badge Visibility — Fixed a strict type-matching bug in the main
auction_list.phpcore file that incorrectly hid the "Timed Auction" badge overlay from valid timed/online auctions on the main upcoming/archive views. The badge now displays properly across all manual and Bidspirit-synced objects when toggled on.
Files Changed
- Modified:
templates/main/auction_list.php
---
[3.2.9.1] — 2026-03-30
Timed Auction Display Enhancements
Features
- Timed Auction Countdown Text Toggle — Added a WP-Admin setting "Change text to 'Auction will close in'" that conditionally changes the countdown label for timed/online auctions on single lot pages.
- Shortcode Text Toggle Support — Extended the new countdown text logic to the
bp_upcoming_wideshortcodes so "Live bidding starts in:" successfully transitions to "Auction will close in:" for timed auctions.
Files Changed
- Modified:
inc/controllers/Settings.php,templates/single-lot.php,templates/shortcodes/upcoming-auction-wide.php,templates/shortcodes/upcoming-auction-wide-manual.php
---
[3.2.9.0] — 2026-03-29
Billing & Invoices Polish
Fixes
- Profile Invoice ID Tracking — Prevented internal auction codes (e.g.
002orai4) from breaking into the clean hyphenated titles inside theprofile-templates.phpview. - Dynamic Payment Statuses — Replaced Bidspirit's default/cached
NOT PAIDHTML payloads by wiring thedompdfgenerator to directly respect the current$b.statusstring from the API (resolving instances where a paid invoice still printed "NOT PAID" atop the document). - Payment Instructions Conditional — Automatically hide the "Payment Instructions" block from the PDF footer when an invoice is fully paid.
- Improved Nomenclature — Changed "Invoice No:" to "Bidder No:" on document output to prevent confusion with static invoice ledger IDs.
---
[3.2.6.0] — 2026-03-28
Multi-Day Auction Lot Filtering Fix
Fixes
- Day 2+ showing lots from Day 1 in multi-day auctions — The
itemIndexcolumn inbp_meta_dataisvarchar(55), but the day-range filter inBidspiritQuery::bp_query_where()was comparing it as a string. With string comparison, lot numbers like'11','101'–'145'incorrectly fell between'1001'and'1450', causing Day 1 lots to leak into Day 2 results. Fixed by usingCAST(bpMeta.itemIndex AS UNSIGNED)for numeric comparison andintval()on the PHP-side boundary values. Letter lots (e.g.14A,1025A) are handled correctly —CASTstrips the suffix, keeping them grouped with their base lot number.
Files Changed
- Modified:
inc/controllers/BidspiritQuery.php
---
[3.2.5.9] — 2026-03-27
Catalog Page Fix
Fixes
- Duplicate preview hours on catalog pages — The
displayHoursfield was rendered twice: once via thebp_after_description_auctionhook inBidspiritViews.phpand once inline in the auction template. Removed the hook-based rendering to eliminate the duplication.
Files Changed
- Modified:
inc/controllers/BidspiritViews.php,templates/main/auction.php
---
[3.2.5] — 2026-03-19
Sync Reliability & Stuck Lot Prevention
Fixes
- CATALOG_PUBLISHED webhook now triggers catalog sync — Previously only sent push notifications without syncing lots. When the earlier AUCTION_CATALOG_UPDATED fired before the catalog was ready on BidSpirit, lots were never imported. CATALOG_PUBLISHED now calls
auctionCatalogUpdated()to trigger a full catalog sync when the catalog is actually available. - 0-lot API results now fail instead of silently succeeding — When BidSpirit API returns 0 lots (catalog not yet ready), the sync job now fails with an explicit error message, allowing the next webhook to create a fresh retry job.
- Expanded CDN allowlist in pre_http_request filter — The HTTP filter during bulk post insertion now allows all
*.bidspirit.comsubdomains and BidSpirit image CDNs (fastly.net,cloudfront.net). Previously onlybidspirit.comandwww.bidspirit.comwere allowed, blocking image downloads during sync and causing worker hangs. - InsertLotsBS timeout guard — Stage 5 (InsertLotsBS processing loop) now has a 180-second timeout and logs progress every 2 batches. Prevents indefinite hangs that previously required manual force-kill.
- fixResult() no longer marks lots as done when postId=0 — When
lotProcessing()fails to create a WP post, the staging row now keepssyncFinished=0so the lot is retried on the next sync pass, instead of being permanently marked as complete with no actual post. - lotProcessing() logs error on missing auction term — Previously returned 0 silently when
Auction::findAuctionById()failed. Now logs an explicit error that feeds intofixResult()to keep the lot retryable. - Hourly orphan detection in safety cron — New step in
syncSafety.phpdetects lot posts that exist inbp_meta_databut are missing their auction taxonomy assignment (caused by workers killed mid-batch) and auto-repairs them withwp_set_object_terms().
Files Changed
- Modified:
inc/controllers/AuctionsAPI.php,inc/sync/CatalogSyncWorker.php,inc/abs/InsertLotsAbstract.php,inc/import/InsertLotsBS.php,crontasks/syncSafety.php
---
[3.2.4] — 2026-03-18
Sync Worker Hang Fix
Fixes
- Sync workers hanging at InsertLotsBS stage — Third-party plugins (Smush Pro, SmartCrawl SEO, WPMU DEV Updates) hook into
wp_insert_post()and make blocking outbound HTTPS calls for every lot processed. With 489+ lots per auction, this caused workers to hang indefinitely on socket reads to WPMU DEV servers (32.193.94.25,32.193.93.106). AddedWP_IMPORTINGconstant at the REST worker entry point and apre_http_requestfilter inCatalogSyncWorkerthat blocks all non-essential external HTTP during the batch post-insertion phase. Loopback (127.0.0.1,localhost) and BidSpirit API calls remain allowed. - Stuck staging rows after force-kill — When workers were force-killed mid-sync, staging rows in
import_historywere left withsyncstart=1and never unblocked. Subsequent sync runs could not see these rows (filtered out byLot::getRawLots()), causing the InsertLotsBS loop to exit immediately with 0 posts processed. Combined with job deduplication (SyncQueue::enqueue()skips if aprocessingjob exists), this created a deadlock where no new sync could proceed.
Files Changed
- Modified:
auctionforge.php,inc/sync/CatalogSyncWorker.php
---
[3.2.2] — 2026-03-17
Full Sync Auction Discovery Fix
Fixes
- Full Sync finds no auctions on fresh sites — The v3
full_syncaction only queried the WordPress database for existing auction terms, but on a freshly deployed site the database has zero auctions. AddedAuctionList::init()discovery step before querying the DB, so Full Sync now fetches all auctions from the BidSpirit API and creates taxonomy terms first, then enqueues catalog sync jobs for each.
Files Changed
- Modified:
auctionforge.php
---
[3.2.0] — 2026-03-14
Webhook Pipeline Fixes, Archive Sync & Admin UI Overhaul
New Features
- Archive Sync — New "Archive Sync" button on Sync Status admin page. Enqueues catalog sync jobs for all ARCHIVED/ENDED auctions. Past auctions now appear in the auction dropdown with an optgroup separator and state label.
- Sync Tasks v3 — Replaced old v2 task cards (importData, importBidSpirit, lotBidSpiritOld) with v3 queue-based tasks. "Sync Active Auctions" and "Sync Archived Auctions" now enqueue jobs via the queue system. Maintenance tasks (Clean Draft/Trash Lots, Clean Orphaned Meta) remain as direct-execution tasks.
- How It Works guide rewritten — Complete rewrite of the admin guide for v3 architecture. Documents webhook-first flow, all 5 job types, queue system mechanics, cron setup (external + WP-Cron), configuration constants, and troubleshooting.
Fixes
- Dual-write removed — Removed legacy handlers from
auctionCatalogUpdated(),auctionDayEnded(), anditemsUpdated()webhook methods. The old handlers were racing with the v3 worker, creating orphaned staging rows inimport_historythat were never processed. All three methods now exclusively use the v3 enqueue → spawn path. - ITEMS_UPDATED webhook — Fixed
itemsUpdated()failing to enqueue jobs. TheITEMS_UPDATEDpayload hasauctionIdnested initemsByLanguage.{lang}[0].item.auctionId, not at the top level. Added extraction logic to resolve it. - ItemUpdateWorker incomplete —
ItemUpdateWorker::process()was only callingLot::bulkSave()(staging table) without runningInsertLotsBSto process staged data into WP posts andbp_meta_data. Added the InsertLotsBS processing step with autocommit restore. Item updates now flow: stage → InsertLotsBS → WP post + meta → cache clear. - Worker spawn reliability — Changed
SyncQueue::spawnWorker()from non-blocking HTTPS to blocking HTTP loopback (http://127.0.0.1with explicitHostheader, 2s timeout). Fixes nginx 403/404 errors when HTTPS loopback hits the default vhost instead of the site's vhost. - API token constant — Plugin expects
AUCTIONFORGE_API_TOKENinwp-config.php(renamed fromUCO_API_TOKENduring the plugin rename). Documented in readme.
Database
- DB version: 22 → 23
Files Changed
- Modified:
inc/controllers/AuctionsAPI.php,inc/sync/ItemUpdateWorker.php,inc/sync/SyncQueue.php,auctionforge.php,admin/view/sync-status.php,readme.txt
---
[3.0.0] — 2025-03-14
New Feature: Webhook-First Sync Architecture (Sync v3)
Overview: Complete redesign of the BidSpirit data synchronisation pipeline. Replaces the old two-phase polling system (importBidSpirit every hour + importData every minute) with a webhook-driven job queue that processes data in near real-time.
Architecture
- 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: webhook → queue → background worker → WordPress posts. - Dual-write mode — During transition, webhooks enqueue jobs AND still run the legacy handlers. Once verified, legacy handlers can be removed cleanly.
- Job deduplication — Prevents duplicate work by checking for existing pending/processing jobs with the same auction_id + job_type.
New Components
- Job Queue System (
inc/sync/SyncQueue.php) — Priority-based FIFO queue with atomic job claiming, status tracking (pending/processing/completed/failed/skipped), worker PID tracking, and automatic stuck job recovery. - Sync Logger (
inc/sync/SyncLogger.php) — Real-time log table for admin console polling with level filtering (info/success/warning/error) and incremental cursor-based retrieval. - Catalog Sync Worker (
inc/sync/CatalogSyncWorker.php) — Processes catalog_sync, full_sync, and day_ended jobs by reusing existingLotList::singleRun()logic. - Item Update Worker (
inc/sync/ItemUpdateWorker.php) — Processes individual item_update jobs with the same logic as the webhookitemsUpdatedhandler. - Background Worker (
crontasks/syncWorker.php) — Async CLI process spawned by webhooks viaexec()or by the safety cron. Claims and processes queued jobs with a configurable timeout (default 240s). - Safety Net (
crontasks/syncSafety.php) — Hourly cron that resets stuck jobs (>10min), spawns workers for pending jobs, runs a 24-hour health check (auto-enqueues full sync if no webhooks received), and purges old data.
Admin UI
- Queue Status Dashboard — New card on Sync Status page showing pending/processing/completed/failed/skipped counts, recent jobs table with real-time refresh, worker status badge, and action buttons:
- Full Sync — Enqueues catalog sync for all active auctions
- Sync Selected — Enqueue a single auction from dropdown
- Spawn Worker — Manually trigger a background worker process
- Live Console — Dark-themed terminal console on the Sync Status page. Polls
af_sync_logevery 1.5s showing timestamped, color-coded log entries from webhooks, workers, queue operations, and the safety cron. Supports pause, clear, and auto-scroll.
Cron Changes
- Removed
importData(ran every minute — ~1,440 PHP executions/day) - Removed
importBidSpirit(ran hourly — ~24 PHP executions/day) - Added
syncSafety(runs hourly at :10 — 24 PHP executions/day) - Net effect: ~62 PHP executions/hour → 1 PHP execution/hour
- WP-Cron safety hook (
auctionforge_sync_safety) — Always-active hourly event, independent of external cron - setup.sh v3 — Updated task definitions, new
migratecommand for interactive v2→v3 transition
Database
- New table:
af_sync_queue— Job queue with status, priority, source, attempts, worker PID, timing columns - New table:
af_sync_log— Real-time log entries with context, level, auction_id, job_id - DB version: 20 → 22
Constants Added
| Constant | Default | Description |
|---|---|---|
|
AUCTIONFORGE_SYNC_WORKER_TIMEOUT| 240 | Worker process timeout in seconds ||
AUCTIONFORGE_SYNC_STALE_JOB| 600 | Seconds before a processing job is considered stuck ||
AUCTIONFORGE_SYNC_HEALTH_CHECK| 86400 | Seconds without webhook before triggering full sync ||
AUCTIONFORGE_SYNC_LOG_RETENTION| 7 | Days to keep log entries ||
AUCTIONFORGE_SYNC_QUEUE_RETENTION| 30 | Days to keep completed queue jobs ||
AUCTIONFORGE_CURL_TIMEOUT| 30 | BidSpirit API cURL timeout in seconds ||
AUCTIONFORGE_PHP_BINARY| /www/server/php/83/bin/php | PHP CLI binary path for spawning workers |AJAX Handlers Added
auctionforge_sync_log_poll— Incremental log polling for live consoleauctionforge_sync_queue_status— Queue counts + recent jobs for dashboardauctionforge_sync_enqueue— Admin-triggered sync actions (full_sync, sync_auction, spawn_worker)
Fixes
- cURL timeout — BidSpiritRequest now enforces a 30-second timeout (was unlimited/0), preventing hung connections from blocking the sync pipeline.
Files Changed
- Modified:
auctionforge.php,inc/coreIncludes.php,inc/controllers/AuctionsAPI.php,inc/BidSpiritRequest.php,admin/view/sync-status.php,crontasks/setup.sh - Created:
inc/sync/SyncQueue.php,inc/sync/SyncLogger.php,inc/sync/CatalogSyncWorker.php,inc/sync/ItemUpdateWorker.php,crontasks/syncWorker.php,crontasks/syncSafety.php
---
[2.7.3.0]
Fixes
- Various stability improvements and bug fixes.
[2.7.1.2]
Fixes
- Added missing
vatAndCommission()function inloadBid()— the sales tax display on single lot pages was never being rendered because the code to callloadTemplateforvat-and-commission-templatewas missing fromapp.js.
[2.7.1.1]
Fixes
- 2 decimal places now only appear in the bid modal (Your max bid, Total Price) via
showDecimalsflag. 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.
[2.7.0.9]
Fixes
- Fixed fatal error during plugin install/upgrade:
class-stats-database.phprequire failure.
[2.7.0.0]
New Features: Advanced Lot Analytics
- Conversion Tracking, Peak Viewing Times, Pre-Sale vs Live Comparison, Category Performance, Share Analytics, Search → View Funnel, Click-Through Tracking, CSV Export, Hot Lot Badge.
- New DB table:
af_lot_shares. New columns onaf_lot_analytics. DB version bumped to 20.
[2.6.0.0]
New Feature: Lot Analytics
- Comprehensive lot view and favorite tracking system with admin dashboard.
[2.5.0.0]
New Features
- Site Statistics System — Full website analytics built into the plugin admin.
- Recently Viewed Items — Profile page tab showing last 20 viewed lots per user.
- Run Identity Check — calls the new wpdeploy
-
v3.7.0.22 Stable May 06, 2026Download v3.7.0.22📦 8.99 MB⚙️ WP 5.2+🔧 PHP 7.2+✓ Tested 6.4
AuctionForge Changelog
All notable changes to the AuctionForge plugin are documented in this file.
---
[3.7.0.21] — 2026-05-05
Added — Connection Diagnostics on the Updates admin page
A new Connection Diagnostics card on Lots → Updates that detects and one-click-heals identity mismatches between this site and the deployment server.
The problem it solves. When a WordPress install is cloned (template → customer site, dev → prod, backup → restore), the cloned wp_options carry the original site's
auctionforge_update_api_keyover to the newhome_url(). The new install then makes API calls to wpdeploy *authenticated as the original site*. wpdeploy looks up by api_key, not by URL, so every/sync-user-tracking,/check-updates,/report-health, and most importantly the Kuma push URL, gets recorded against the WRONGwpdeploy.sitesrow. The cloned site's monitor stays silent; the original's monitor shows traffic that isn't from it.What the diagnostic does:
- Run Identity Check — calls the new wpdeploy
GET /api.php/whoamiendpoint and compares the returnedcaller_site_urlagainsthome_url(). Renders a verdict ("matches" / "MISMATCH") plus the full server-side view (site_id, site_name, last_check, plugin version on file, remote IP). The "Re-register & Reset Kuma" button only appears if there's a mismatch. - Re-register & Reset Kuma — calls
/request-access(which is idempotent onsite_url— wpdeploy returns the canonical api_key for *this*home_url(), regardless of whatever wrong key we were holding), wipesauctionforge_kuma_push_urland any leftover heartbeat cron events, then immediately fires/check-updatesso the api_request interceptor catches the freshly-correct kuma_push_url for *this* site. The keepalive mu-plugin's heartbeat picks it up on the next 60s tick.
Internal
AuctionForge_Auto_Updater::whoami()(new) — thin wrapper overapi_request('whoami', [], 'GET'). Returns the parsed wpdeploy/whoamipayload.AuctionForge_Auto_Updater::reset_connection()(new) — three-step heal: re-register → wipe Kuma cached state → re-fetch via/check-updates. Returns shape suitable forwp_send_json_success.- Two new AJAX actions:
auctionforge_diagnose_connection,auctionforge_fix_connection. Both behindmanage_optionscapability + nonce check. auctionforge_normalize_host()helper for case/scheme/www-tolerant URL comparison.
Server-side companion
Requires the wpdeploy
/api.php/whoamiendpoint added in the same release window. The endpoint is gated behind whatever api_key the caller already presented (a master key returnstype=masterwith no site row; a per-site key returns the site row that key resolves to). Reveals nothing the caller doesn't already implicitly authenticate against.---
[3.7.0.20] — 2026-05-04
Changed
- Kuma heartbeat path is now wpdeploy-independent. The actual heartbeat firing — wp-cron schedule, page-load piggy-back, outbound HTTP — moved out of AF and into the AuctionForge Keepalive mu-plugin (
wp-content/mu-plugins/auctionforge-keepalive.php, bumped to v1.2.1). Once a site has been provisioned once andauctionforge_kuma_push_urlis cached locally, the heartbeat keeps reporting forever even if AF is deactivated, mid-upgrade, deleted from disk, or wpdeploy is offline. The mu-plugin can't be deactivated by WordPress, can't be broken by an AF release, and depends on AF for nothing. - AF only writes the
kuma_push_urloption now. It no longer schedules the cron, no longer fires the heartbeat, and no longer holds any heartbeat-related state. Theapi_request()interceptor still catcheskuma_push_urlfrom/check-updatesand/report-healthresponses and persists it; the mu-plugin reads it from there. - Migration block.
init_hooks()clears any leftoverauctionforge_kuma_heartbeatwp-cron event from AF ≤ 3.7.0.19 on first plugin load after upgrade. The mu-plugin runs the same clear on its ownplugins_loadedhook — belt and braces. The new event the mu-plugin schedules iskuma_heartbeat_tickon a newkuma_60sschedule. AuctionForge_Auto_Updater::kuma_heartbeat()no-opped. Kept as a safety landing pad so any staleauctionforge_kuma_heartbeatwp-cron event that fires one last time before migration kicks in doesn't trip a "no callback registered" warning. Real heartbeat work happens in the mu-plugin.
Added — operator override
AUCTIONFORGE_KUMA_PUSH_URLconstant. Define it inwp-config.phpto point a site directly at Kuma without ever involving wpdeploy:
```php
define('AUCTIONFORGE_KUMA_PUSH_URL', 'https://kuma.example.com/api/push/<token>?status=up&msg=&ping=');
```
The constant takes precedence over the
auctionforge_kuma_push_urloption. With it set, the site can be operated fully outside wpdeploy — useful for one-off installs, customer-managed sites, or disaster-recovery scenarios where wpdeploy is unreachable for an extended period.Internal — Keepalive mu-plugin v1.2.1
The bundled keepalive template at
inc/keepalive/auctionforge-keepalive.template.phpnow also handles Kuma heartbeats. Three layered triggers ensure cadence stays tight regardless of site traffic:1. Dedicated wp-cron event
kuma_heartbeat_tickon a new 60-secondkuma_60sschedule2. Page-load piggy-back on
init: any request older than 50s since the last beat fires another, transient-guarded so concurrent hits coalesce. Free on busy sites; rescues low-traffic sites the moment any visitor arrives.3. Self-heal inside the cron callback: if the event somehow gets cleared, re-arm it before sending the beat.
HTTP is
timeout=2, blocking=false— fire-and-forget, never slows page loads. External IP introspection (ipify → ifconfig.me → icanhazip fallback chain, 24h transient cache) is duplicated in the mu-plugin so it doesn't depend on AF being loaded for the IP lookup.The keepalive installer (
class-keepalive-installer.php) detects theKEEPALIVE_VERSION: 1.2.1header bump and idempotently overwrites every site's mu-plugin on the next AF load. No manual reactivation needed.Failure modes after this release
| State | Heartbeat? |
|---|---|
| AF active and healthy | ✅ via mu-plugin |
| AF deactivated by an operator | ✅ mu-plugin runs anyway |
| AF deleted from disk | ✅ as long as
auctionforge_kuma_push_urloption exists OR constant is set || AF mid-upgrade / partial install | ✅ mu-plugin doesn't depend on AF code paths |
| wpdeploy down (existing site) | ✅ option is cached locally, no wpdeploy round-trip |
| wpdeploy down (brand-new site, never provisioned) | ❌ first-time URL provisioning still needs wpdeploy. One-shot, accepted trade-off. |
| Site has zero traffic AND wp-cron isn't firing | ❌ truly nothing to trigger a beat. Mitigation is OS-level cron / DISABLE_WP_CRON, out of scope here. |
---
[3.7.0.19] — 2026-05-04
Changed
- Reverted Kuma heartbeat cadence: 3 min → 1 min.
auctionforge_kuma_heartbeatis back on thebp_minutelyschedule. With Kuma's 310s silence window, 60s cadence tolerates 4 missed wp-cron ticks before flipping a monitor red — the original "give-it-leeway" semantics. The 3-min cadence introduced in 3.7.0.18 was strictly less chatty but tighter (a single missed tick would trip Kuma), and the trade-off wasn't worth it operationally. - Migration block updated.
init_hooks()now detects any existing event scheduled on a non-bp_minutelycadence (e.g. thebp_3_minutelyset by 3.7.0.18) and re-schedules ontobp_minutely. Sites that took 3.7.0.18 roll back automatically on first plugin load after upgrade. - First-fire jitter narrowed back to 0–60s to match the new cadence.
Notes
- The
bp_3_minutelycron schedule registration inauctionforge.phpis kept (harmless; available for future use). Only the heartbeat scheduling sites have been reverted. - Apparent latency in Kuma flipping a monitor red after a real outage is governed by Kuma's per-monitor
interval(silence-detection window, currently 310s on the wpdeploy/Kuma side), not by this cron's cadence. To detect outages faster, lower the Kumainterval; to add more tolerance to wp-cron drift, raise it.
---
[3.7.0.18] — 2026-05-04
Changed
- Kuma heartbeat cron cadence: 1 min → 3 min.
auctionforge_kuma_heartbeatnow runs on a newbp_3_minutelyschedule (180s) instead ofbp_minutely(60s). This pairs with Kuma's 310s silence-detection window — a single late wp-cron tick (3 min + drift) still lands inside the threshold, but normal traffic to Kuma drops by ~3×. - Random first-fire offset widened from 60s → 180s. With ~50 sites on a single Kuma instance, spreading first-fires across the full 3-min window prevents synchronised bursts every 3 minutes.
- Auto-migration of existing scheduled events. On plugin upgrade
init_hooks()callswp_get_scheduled_event('auctionforge_kuma_heartbeat')and, if the existing event is onbp_minutely, clears it and reschedules ontobp_3_minutely. Idempotent — a no-op once migrated.
Internal
- New cron schedule registered:
bp_3_minutely(BP_MINUTELY * 3= 180s). Defined alongside the existingbp_minutely/bp_ten_minutely/bp_hourly/bp_24_hourlyschedules inauctionforge.php.
---
[3.7.0.17] — 2026-05-04
Fix: "Install Now" always returned
up_to_dateThe
/sync/versionREST endpoint (called by wpdeploy's Install Now button) was always respondingsuccess: false, reason: up_to_dateregardless of the actual installed version, defeating the button's whole purpose.Root cause
rest_force_plugin_update()did:```
delete_site_transient('update_plugins');
$this->check_pending_updates();
$updates = get_site_transient('update_plugins');
```
check_pending_updates()calls the/pending-updatesendpoint on wpdeploy (which returns the deploy queue), but it does not touch the WPupdate_pluginstransient. The transient just got deleted on the line above and never gets re-populated, so theisset($updates->response[…])check always failed → always returnedup_to_date.Fix
- Use
wp_update_plugins()instead — that's what fires thepre_set_site_transient_update_pluginsfilter chain that AF's owncheck_for_updates()callback hooks into to seed the transient. Same pattern is already used correctly ininstall_update()at line 280. - Belt-and-braces: when the request body carries an explicit target
versionand that version is strictly greater than the on-disk plugin version (perversion_compare), bypass the transient check and force the install. This handles edge cases where the transient seeding fails (network blip during the wp-cron cycle, hosting-side cache, etc.) so the explicit Install Now command still does what it says.
---
[3.7.0.16] — 2026-05-04
Server external IP reported to wpdeploy + included in Kuma heartbeats
Each AF install now reports its server's outbound external IP. Two channels:
1. Kuma heartbeat
msg— the per-minute push payload now reads<wp_version>|<plugin_version>|<external_ip>(e.g.6.9.4|3.7.0.16|152.53.187.82) so you can spot at a glance which physical box each site lives on. When a host goes dark, multiple monitors flip red simultaneously with the same IP — instant root-cause hint.2.
/report-healthpayload — a newexternal_ipfield that wpdeploy stores onsites.external_ip. Visible in the Sites admin view as a tappable IP chip; clicking it filters the table to all sites sharing that IP.How the IP is detected
AuctionForge_Auto_Updater::get_external_ip()calls one of three public echo services in turn —api.ipify.org,ifconfig.me/ip,icanhazip.com— with a 4-second timeout each. The first one that returns a valid IP wins. Result is cached in a transient for 24 hours so we don't hit external services on every report cycle.Wpdeploy fallback for older plugins
/report-healthnow also capturesREMOTE_ADDR(orHTTP_CF_CONNECTING_IPwhen behind Cloudflare) when the payload doesn't includeexternal_ip. So sites still on 3.7.0.15 or older start populating their IP today via the same route, no plugin update needed for that data path.---
[3.7.0.15] — 2026-05-04
Kuma monitors land in an "Unallocated" group by default
New AuctionForge installs are auto-enrolled into Kuma under a new top-level group called Unallocated so the operator can review them and drag-drop into the right home (Bidspirit Auction Sites, Stephen's Auctions, Misc Websites, etc.) before classification. Without this every new monitor would appear at the dashboard top level alongside whatever group hierarchy already exists.
What changed (wpdeploy-side, no plugin behaviour change)
KumaProvisionernow ensures an "Unallocated" group exists in Kuma (find-or-create via the same Socket.IOaddpath used for monitors, withtype='group') before provisioning each new push monitor, and passesparent=<group_id>in theaddpayload so the new monitor lands inside it.- The Node helper accepts arbitrary
typeandparentfields on the input payload (previously hardcoded totype='push'). - The group itself gets the same
user_id=1reassignment so it shows up on the human admin's dashboard.
Existing Clumber monitor (id=71) was migrated into the new group as part of this release.
This is a wpdeploy infrastructure change — the AF plugin code is unchanged from 3.7.0.14. Version bumped only to mark a clean snapshot point.
---
[3.7.0.14] — 2026-05-04
Uptime Kuma push heartbeat with automatic enrolment
Each AF install now appears as its own monitor on the central Uptime Kuma at https://kuma.smoothbyteit.dev, beating every minute and flipping red within ~90 seconds when a site goes dark. Auto-enrolled — no manual Kuma UI clicks per site.
How it works
1. First contact: when the plugin calls
/request-accessor/report-health, wpdeploy's newKumaProvisioneropens a Socket.IO connection to Kuma as a dedicatedauctionforge-botuser, calls the officialaddevent, and gets back a fresh push token. The resulting URL is shipped to the plugin in the JSON response askuma_push_url.2. Plugin-side: a generic interceptor on
api_request()persistskuma_push_urlto the optionauctionforge_kuma_push_urlwhenever it appears in any wpdeploy response, and immediately schedules the newauctionforge_kuma_heartbeatcron on the existingbp_minutelyinterval.3. Heartbeat: the cron handler sends a single
wp_remote_getto the push URL each minute withmsg=<wp_version>|<plugin_version>so Kuma's dashboard shows the running stack at a glance. Kuma's silence-detection window is 90s, so a single missed wp-cron tick won't false-DOWN.4. Idempotency: the Kuma monitor's
descriptionfield storeswpdeploy_site_id:<id>. Re-registering the same site short-circuits at the wpdeploy layer (existingkuma_monitor_idonsites), or — if that's missing — Kuma's existing row is reattached via the description anchor. Re-installing the plugin never duplicates monitors.Why Socket.IO and not direct DB insert
Kuma's monitor scheduler does not poll its own DB for new rows —
startMonitors()only loads monitors at boot, and new ones are armed via the authenticated Socket.IOaddevent handler (which callsstartMonitor()and arms the per-monitorsafeBeatsetTimeout). A direct INSERT would create a "phantom" monitor that accepts pushes but never flips DOWN on silence, defeating the whole feature.Notifications + monitor ownership
Provisioner reads existing Kuma notification rows whose channel is Telegram (or marked default-for-new-monitors) and attaches them to every new monitor via the
addevent'snotificationIDList. After the Socket.IOaddsucceeds, the provisioner direct-writesuser_id=1to the new monitor row in Kuma's SQLite — Kuma'saddhandler hardcodesuser_id=socket.userID(the bot at user 2), which causes the frontend's real-time monitor-list updates to skip the admin's session. The follow-up UPDATE stamps ownership to the human admin so monitors render with their full name on the admin dashboard immediately.Failure modes
Every call boundary degrades safely. If Kuma is unreachable when a site registers, registration completes without
kuma_push_url; the next twicedaily/report-healthretries. Heartbeat HTTP failures are silent (which is the desired outcome — Kuma's silence-detection is the signal). Kuma reset / monitor row deleted: provisioner's pre-flight check NULLs the wpdeploy anchors and falls through to fresh provisioning on the next call.Operator setup
Already done: the
auctionforge-botKuma user has been created and credentials populated in wpdeploy'sconfig.php. To rotate or migrate Kuma later, editKUMA_URL/KUMA_BOT_USER/KUMA_BOT_PASSinconfig.php— no plugin redeploy needed.---
[3.7.0.13] — 2026-05-04
Wide shortcode: hide Register button for logged-in users
- When a user is logged in to BidSpirit (
body.bp-login), the Register button is now automatically hidden on wide-format auction cards (bp_upcoming_wideandbp_auction_list layout="wide"). - The View Catalog / Catalog Coming Soon button expands to full width when the Register button is hidden.
- Uses a lightweight
MutationObserverto react to BidSpirit's async session init. - Applied to both
UpcomingAuctionWide.phpandAuctionList.phpshortcode CSS blocks.
---
[3.7.0.12] — 2026-05-03
Stop-word denylist for BidSpirit category-tag concatenations
BidSpirit's
wp_bp_meta_data.tagsfield arrives as PascalCase category names lowercased without separators (uscollectibles,firearmsaccessoriesammunition,usdecorativearts,printsandmultiples). They look like keywords but they're really categories, and on sites where the tags field is populated they completely swamp the top-5 chips for power users (e.g. one buyer's profile was led byuscollectibles 453 viewsdespite that being a label rather than a real interest signal).29 known patterns added to
stop-words.phpso the tokenizer drops them at extraction time. New ones surfacing from sites we haven't seen yet should be added here as they appear; the wpdeploy?tab=keywordscorpus page makes them easy to spot (sort by most users with low lots count and look for non-word concatenations).---
[3.7.0.11] — 2026-05-03
Keyword extractor — capture model years + hyphenated calibers, drop more auction noise
The People view's top-5 keyword chips were filling up with generic descriptors (
household,model,original,assortment) instead of the brand/maker terms (mauser,whitworth,colt) that actually distinguish one buyer from another. Live-data review on the new?tab=keywordsKeyword Corpus page on wpdeploy confirmed the cause: real signal was being lost at the tokenizer stage.Tokenizer changes (
inc/stats/class-keyword-extractor.php)Three pre-passes now run before the standard split-on-non-alpha:
1. Hyphenated / x-separated calibers —
.45-70,.30-06,7.62x54r,8x57. Without this they're split into pure-digit fragments and dropped, losing the actual model identifier.2. Caliber-with-suffix —
9mm,.22lr,.45acp,.380acp. Previously only survived by accident because of the trailing letters; now extracted explicitly.3. 4-digit model years 1700–2099 —
1873,1903,1911,1971. Pure-digit tokens were unconditionally dropped; now retained when year-shaped.Standard pass relaxed to allow 4-digit pure-digit tokens between 1700 and 2099.
Stop-word additions (
inc/stats/stop-words.php)Conservative — only universally empty auction descriptors:
original,marked,accessories,decorative,household,goods,made,condition,assortmentDeliberately NOT added:
antique,vintage,rare,fine— those carry buyer-segmentation signal (antiquarian buyers vs. modern-collectibles buyers). Borderline cases (metal,wooden,american,model) are left to the wpdeploy-side IDF re-rank.Companion change on wpdeploy (no plugin update needed)
refresh_people_rollup.phpnow multiplies each keyword's score by an IDF factor pulled fromkeyword_idf(refreshed hourly byrefresh_lot_keyword_index.php). Generic keywords that appear in many lots get demoted automatically; brand/maker words that only appear on a handful get lifted into the top-5 chips.After deploying this version, reset the
auctionforge_lots_sync_watermarkoption on each site and clear thewp_af_stats_lot_keywordstable to force re-extraction of every lot through the new tokenizer.---
[3.7.0.10] — 2026-05-03
Lots sync — ship resolved CDN image URL, not bare BidSpirit filename
class-lots-sync.phpwas sendingimagesListStr's first comma-token verbatim asimage_url— that's the raw BidSpirit storage value (e.g.001.jpg). Wpdeploy received a bare filename, the browser resolved it against the wpdeploy host, and every lot thumbnail 404'd.The lots-sync now instantiates
LotImageand pulls the resolved CDN URL (LABEL_MEDIUMthumbnail), with fallback toLABEL_ORIGINALand a final defensive check that drops anything that doesn't start withhttp(s)://. Resolution is wrapped in try/catch — a missing class or BidSpirit settings issue leavesimage_urlempty rather than blowing up the sync batch.After deploying this version on a site, reset its
auctionforge_lots_sync_watermarkoption (delete the row) to re-push existing lots through the new resolver. The wpdeploy view skips<img>rendering whenimage_urlisn't a real URL, so dirty rows degrade silently while the watermark catches up.---
[3.7.0.9] — 2026-05-03
Keepalive sweep — auto-clears WP upgrader debris that produces silent "Could not create directory" failures
WordPress 6.x's atomic-rollback flow leaves
wp-content/upgrade-temp-backup/lying around when its post-install cleanup misfires (the user-facing symptom is "Update failed: Could not create directory" after an update that has actually already succeeded). Stalewp-content/upgrade/<plugin>-tmp/and.maintenancelockfiles from crashed upgrades cause the *next* upgrade attempt to fail the same way. None of WP's own scheduled cleanup catches these reliably.The keepalive mu-plugin (
KEEPALIVE_VERSION1.1.0) now sweeps all three classes of debris on every page load, transient-guarded to once per hour. Safety thresholds prevent it touching anything actually in flight:.maintenancefiles less than 5 min old,wp-content/upgrade/*entries less than 60 min old, andupgrade-temp-backup/less than 30 min old are left alone. Wrapped in try/catch with no throws, so the sweep can never block a request.The keepalive installer detects the version bump and rewrites
wp-content/mu-plugins/auctionforge-keepalive.phpautomatically on the next AF load, no manual reactivation needed.---
[3.7.0.8] — 2026-05-03
Shop auction UI refinements & share button settings
Shop (Buy-It-Now) catalog improvements
- Shop sorting dropdown: Added a dedicated sorting dropdown for shop catalogs with options: Recently Added, Price: High, and Price: Low. Sorts by
buyoutPricemetadata. Regular auction catalogs retain the original sorting options. - Removed "Buyout price:" label: On shop lot pages, the redundant "Buyout price:" text before the price is now hidden. Only the price and "Buy Now" button are displayed. Regular auction buyout lots still show the label.
- Removed increments table & terms links: On shop lot pages, the "Increments table" and "Terms and conditions" links are hidden since they don't apply to buy-it-now items. The "Make an inquiry" link remains.
Buyout confirmation modal overhaul
- Sales tax logic: The buyout confirmation modal now follows the same sales tax detection as the regular bid modal. When the auction house has a US state configured, displays "Sales Tax" instead of "VAT", with the correct percentage for same-state buyers and 0% for out-of-state.
- Hide 0% buyer's premium: The Buyer's Premium line is hidden when the commission is 0%.
- Shop-specific text: For shop buyouts, all disclaimer text is replaced with: *"You will receive an email with your invoice, including shipping, and a secure payment link."*
- Shop-specific buttons: "I don't Agree" → "Cancel", "I Agree" → "Buy". The "Terms of sale" button is removed for shop buyouts. Non-shop buyouts retain the original layout.
Purchase confirmed screen
- Title changed from "Confirm purchase:" to "Purchase Confirmed".
- Thank you message updated to: *"Thank you for your order. We will confirm your order within 1-2 business days and email you an invoice, including shipping, and a secure payment link."*
Share button settings (Appearance tab)
- Added a Share Buttons section to the BidSpirit Appearance settings tab with individual checkboxes for each sharing platform: Copy Link, WhatsApp, Facebook, Telegram, X (Twitter), VK, Pinterest, and Email.
- All platforms default to enabled (shown). Unchecking a platform hides that share button on all lot pages (both shop and regular auctions).
---
[3.7.0.7] — 2026-05-02
Identity stitch on bidder login — keyword interest tallying now actually fires
Why
The keyword extractor was filling
wp_af_stats_lot_keywordscorrectly (197 lots, 734 distinct keywords on Clumber), butwp_af_user_interestsandwp_af_user_recent_activitywere both empty — zero rows of any dimension. Same on every site running the new sync streams.Root cause: identity stitching (visitor_hash → email) only fired in the tracker AJAX when
is_user_logged_in()returned true. On these auction sites the actual bidders authenticate via BidSpirit, never aswp_users— so the WP login check was always false, the stitch table stayed empty, andmaybe_record_lot_view($url, $email, …)got called with an empty email and bailed out before tallying. Lot views by real bidders never landed in the user-side interest profile.What changed (no auth-path intervention)
The fix piggybacks on the *existing* fire-and-forget tracking AJAX that already runs after a successful BidSpirit login (
afLogIP("login", bidspiritUser)). It does not touch the BidSpirit auth path itself.inc/ip-logger.phpauctionforge_ajax_log_ip()— after the existingauctionforge_user_trackinginsert, if the request carries avisitor_hashand the email is valid, callsAF_Stats_Visitor_Email_Map::record($vh, $email, $ip). Wrapped in try/catch so any failure here can never break the existing tracking response.assets/js/app.js+src/js/app.jsafLogIP()— readslocalStorage['af_vid'](defensively, ITP/private-mode safe) and includes it asvisitor_hashin the POST body.inc/stats/class-stats-init.phpmaybe_record_lot_view()— when$emailis empty (the common case for BidSpirit-only bidders) but avisitor_hashis present, falls back toAF_Stats_Visitor_Email_Map::lookup($visitor_hash). If a stitch exists, the view tallies; if not, it stays anonymous.
Net effect: a bidder logs in (BidSpirit), the post-login tracker AJAX fires as it always has, and now also writes one extra row into
af_stats_visitor_emails. From that point onward, every page they view on the same browser/device tallies intoaf_user_interestskeyed on their email. The BidSpirit transaction itself is untouched.---
[3.7.0.6] — 2026-05-02
Critical fix —
X-API-Keyheader collision with sibling SmoothByte pluginsWhat was wrong
On any site running both AuctionForge and another SmoothByte-stack plugin that also points its updater at
wpdeploy.smoothbyteit.dev(e.g.seo-aeo-optimizer), the second plugin'shttp_request_argsfilter overwrote AuctionForge'sX-API-Keyheader on every outbound API call. Wpdeploy then 401'd because the key it received belonged to a different plugin instance — usually aseo_aeo_update_api_keythat wpdeploy had no record of.The symptom was a quiet, total auth failure:
report-health,check-updates, everysync-*route, all 401. The watchdog flagged streams as "gone" and updates stopped flowing. Affected sites: any install where the AuctionForge key and the sibling plugin's key happen to differ. Sites where both plugins shared a key were silently safe (the overwrite was a no-op).Fix
AuctionForge_Auto_Updater::add_download_auth()now refuses to clobber an existingX-API-Keyand, for download URLs, only stamps when the URL slug matches our own. That keeps targeted calls fromapi_request()intact regardless of filter ordering, and prevents either plugin from writing its key onto the other's download URL.The same fix has been applied to
seo-aeo-optimizerso both ends of the collision are defensive.---
[3.7.0.5] — 2026-05-02
Sync Status admin panel — diagnostic + manual triggers in wp-admin
Why
Diagnosing sync issues used to require shell access on the site or piecing together state from wpdeploy's app.log. This release surfaces the same diagnostics inside wp-admin so a site admin (or anyone with
manage_options) can see exactly what's happening and trigger fixes in one click.Lives inside the existing Sync Status menu (
Lots → Sync Status) — appended below the existing content as a "Sync Diagnostics & Manual Controls" section, no duplicate menu entry.What's on the panel
Connection summary — plugin version,
af_stats_db_version, wpdeploy server URL, last 8 chars of API key, keepalive install state + auto-reactivation count.Sync streams table — for each of the 10 cron hooks (user-tracking, user-profile, user-interests, user-activity, lots, bids+wins, vulnerabilities, report-health, check-updates, fraud-enforcement):
- Configured schedule
- Last fired timestamp + status colour-coded (green=success, blue=idle/empty, red=error)
- Record count from last run
- Next scheduled run
- Current watermark (where applicable)
- "Fire now" button — clears doing_cron, calls
do_action($hook)synchronously, shows the result
One-shot utilities
Test wpdeploy connection— calls/api.php/infowith the site's API keyClear stuck cron lock— deletes thedoing_crontransient (the classic fix when scheduled events stop firing)Reinstall keepalive— overwritesmu-plugins/auctionforge-keepalive.phpfrom the bundled templateBackfill bids from legacy tracking— replayslast_event_type='bid'rows fromwp_auctionforge_user_trackingintowp_af_bid_eventsso the bids-wins stream picks them up. Useful for sites that have years of bid history in the legacy table but nothing in the new queueRun all due events now— clears doing_cron and fires everyauctionforge_*cron event whose timestamp is past due, in one go
Live response output panel shows the JSON returned from each action so you can see what just happened without leaving the page.
Files Changed
- Created:
inc/admin/class-sync-status-page.php - Modified:
inc/stats/class-stats-init.php(load + init the panel) - Modified:
admin/view/sync-status.php(appendAF_Sync_Status_Page::render_panel()call at the bottom) - Modified:
auctionforge.php(Version 3.7.0.4 → 3.7.0.5)
Verification
Navigate to Lots → Sync Status in wp-admin on any 3.7.0.5 site. Scroll past the existing content to the new "Sync Diagnostics & Manual Controls" section. Click "Test wpdeploy connection" — you should see
{"success": true, "auth_type": "site"}. Click "Fire now" on any stream — the row's last-fired timestamp should refresh after 1–2 seconds.---
[3.7.0.4] — 2026-05-02
Self-healing: failed plugin updates can no longer take a site offline
Why
WordPress's plugin updater isn't transactional — when an update fails partway (corrupt unzip, fatal during the new version's
plugins_loaded, disk pressure, theme conflict, etc.) WP often deactivates the plugin and leaves the site without it. Once AuctionForge is dropped fromactive_plugins, no AF code runs again — including its sync handlers — until someone notices and reactivates manually. On the AuctionForge site fleet, this had quietly happened to ~5 sites we found; almost certainly more on production sites we don't have filesystem access to.This release ships an autonomous watchdog that lives outside the AuctionForge plugin entirely so it survives even when AF gets knocked out.
What changed
1. Self-installing keepalive (mu-plugin)
inc/keepalive/auctionforge-keepalive.template.php— a 50-line WordPress must-use plugin. Lives inwp-content/mu-plugins/, which WordPress can't deactivate. On everyplugins_loaded(priority 1, before any regular plugin), it checks: isauctionforge/auctionforge.phpon disk but missing fromactive_plugins? If yes AND the file has a validPlugin Name:header (smoke check — don't reactivate a corrupt zip), it re-adds AF andincludes the file in the same request.inc/keepalive/class-keepalive-installer.php— runs on every successful AF load. Copies the template intowp-content/mu-plugins/auctionforge-keepalive.phpif missing or version-bumped. Idempotent: comparesKEEPALIVE_VERSIONheaders, only writes on change. Refuses to overwrite a foreign mu-plugin (defensive against name collisions). Failure is non-fatal — install errors are recorded inwp_optionsfor wpdeploy visibility but never throw.
Net effect. Any site that successfully loads AF 3.7.0.4 or later will have the keepalive permanently installed in mu-plugins. From that point forward, even if a future update hard-fails, the keepalive recovers AF on the next pageview without any manual intervention or filesystem access. Crucially: this works on sites we don't own — the keepalive ships inside the AF zip, gets installed during the first successful update, and lives in mu-plugins thereafter.
2. Forensic markers
The keepalive writes three options on each recovery:
auctionforge_auto_reactivated_at— most recent recovery timestampauctionforge_auto_reactivated_count— total recoveriesauctionforge_auto_reactivated_failed_at— set when the keepalive saw AF on disk but with no Plugin Name header (genuinely corrupt — needs operator attention)
These get picked up by the AF sync streams and surfaced on the wpdeploy dashboard so you can see which sites have been quietly recovering themselves and whether a particular release is failing more than it should.
3. Companion: post-update-silence alerts on wpdeploy (server side)
Wpdeploy's
report-healthroute now compares incomingplugin_versionagainst the row and writeslast_version_changed_at+previous_plugin_versionon change. TheSyncWatchdogcron then alerts if a site has reported a version change but not sent any heartbeat for 2+ hours since — likely a failed install. Emitssync_incidentsrows withkind=post_update_failureso the existing Telegram fan-out picks them up. Each version-change event alerts at most once.Files Changed
- Created:
inc/keepalive/auctionforge-keepalive.template.php,inc/keepalive/class-keepalive-installer.php - Modified:
inc/stats/class-stats-init.php(callAF_Keepalive_Installer::maybe_install()on every plugin load) - Modified:
auctionforge.php(Version 3.7.0.3 → 3.7.0.4)
Companion server-side changes (already deployed on wpdeploy.smoothbyteit.dev — not in this zip):
sitestable:last_version_changed_at TIMESTAMP NULL,previous_plugin_version VARCHAR(20) NULLapi.php/report-health route detects version changesSyncWatchdog::maybe_alert_post_update_failure()emits the new alert kind
Verification
1. Drop a 3.7.0.4 install on any site. Confirm
wp-content/mu-plugins/auctionforge-keepalive.phpexists post-load.2. Manually deactivate AF from the database (
DELETE FROM wp_options ...active_plugins...). Hit the homepage. AF reappears inactive_plugins;auctionforge_auto_reactivated_countincrements.3. Delete
mu-plugins/auctionforge-keepalive.php. Trigger AF load (any pageview). The file reappears.4. Bump KEEPALIVE_VERSION in the source template, ship a new release, observe the installed mu-plugin update on next AF load.
Operator notes
- Sites currently in the broken state (AF deactivated, no keepalive yet) are NOT auto-rescued by this release — they need a one-time manual reactivation in wp-admin OR a fresh AF install via wp-admin's Upload Plugin. After that, the keepalive is in place and future failures self-heal.
- The post-update-failure alert won't fire for upgrades that happened before this release (no
last_version_changed_atwas recorded). It activates from the first version change wpdeploy sees from each site after this update lands.
---
[3.7.0.3] — 2026-05-02
Fix: profile re-sync on login / profile-edit / register (no more empty names)
Why
The hourly profile sync uses a
user_registeredwatermark — once a user has been pushed once, the watermark advances past them and they're never re-pulled. That meant:1. Existing users whose first_name/last_name became populated AFTER their first sync stayed empty on wpdeploy forever.
2. BidSpirit-driven sites that don't write WP's standard
first_name/last_namefields shipped empty rows even though the canonical name was visible indisplay_name.The People view was showing
—for the name on rows that absolutely had a name available — just not where the sync handler was looking.Fixes (
inc/sync/class-profile-sync.php+inc/stats/class-stats-init.php)AF_Profile_Sync::push_for_user_id($user_id, $blocking=false)— new public method that builds a single user's profile row, normalises it, and POSTs to wpdeploy bypassing the watermark. Non-blocking by default (wp_remote_postwithblocking=false, timeout=2s) so login latency is unaffected.build_user_row($user_id)extracted as a reusable helper. Both the hourly batch and the on-demand push call it. Centralises role-filtering + display_name fallback + usermeta probing.display_namefallback. Whenwp_usermeta.first_name/last_nameare both empty (typical on BidSpirit-only sites),build_user_row()parsesdisplay_name("John Smith" → first=John, last=Smith) so we don't ship a row with a blank name when the data is sitting on the user record itself.- Three new action hooks registered in
class-stats-init.php::init(): wp_login→push_for_user_id($user->ID)— every login refreshes the rowprofile_update→ same — profile edits in wp-admin refreshuser_register→ same — new registrations get pushed instantly (instead of waiting up to 60 min for the next cron tick)
Files Changed
- Modified:
inc/sync/class-profile-sync.php(refactor + new method + display_name fallback) - Modified:
inc/stats/class-stats-init.php(three new action hooks) - Modified:
auctionforge.php(Version 3.7.0.2 → 3.7.0.3)
Verification
1. On a 3.7.0.3 site, find a user whose
wpdeploy.user_profiles.first_nameis empty:SELECT site_id, email, first_name FROM user_profiles WHERE email='something@example.com'2. Log in as that user (or have them log in).
3. Within ~2 seconds, re-query —
first_nameshould now be populated, either from the standard meta key OR parsed fromdisplay_name.4. The non-blocking POST means the user's login experience is unchanged — no spinner, no extra latency.
Operator note
Existing wpdeploy rows with empty
first_name/last_namewill refresh automatically as users log in or edit their profile. To force a one-shot re-walk of every user on a site (regardless of watermark), reset the watermark there:DELETE FROM wp_options WHERE option_name='auctionforge_profile_sync_watermark';Next hourly cron will re-pull every non-admin user with the new fallback applied.
---
[3.7.0.2] — 2026-05-02
Fix: sync-lots datetime mismatch + idle syncs now heartbeat
Why
Two issues surfaced in the wpdeploy Sync Health dashboard:
1. Every site's
sync-lotswas stuck onapi_error. The plugin sendslast_modifiedstraight fromwp_bp_meta_data.lastUpdate, which is a Unix epoch string ("1756919754"). wpdeploy'slots.last_modifiedcolumn is aDATETIME, so MariaDB rejects the insert withSQLSTATE[22007]: Incorrect datetime value. The handler recordsapi_errorand the watermark never advances, so every cron tick re-fails on the same batch.2. Sites with nothing to sync looked dead. When a sync handler had an empty batch (e.g. no non-admin users yet) it was returning early without POSTing anything. wpdeploy's
update_sync_health()only fires on a successful POST, sosites.sync_health_jsonstayed NULL and the dashboard showed grey dots — indistinguishable from a broken cron. WP-Cron was actually firing fine; the watchdog just couldn't tell.Fixes
inc/sync/class-lots-sync.php— newepoch_to_datetime()helper converts the BidSpirit epoch field to UTCY-m-d H:i:sbefore shipping. Idempotent: already-formatted datetimes pass through untouched, invalid values becomeNULL.inc/sync/class-sync-base.php::run()— always POST, even when the batch is empty. Empty payload is{records: []}and wpdeploy's existing handlers handle it gracefully (loop is skipped,update_sync_health()still fires withsynced=0). This makes the dashboard reflect cron liveness, not just data flow.
Files Changed
- Modified:
inc/sync/class-lots-sync.php - Modified:
inc/sync/class-sync-base.php - Modified:
auctionforge.php(Version 3.7.0.1 → 3.7.0.2)
Verification
1. On Clumber:
do_action('auctionforge_sync_lots')— confirm the previousauctionforge_last_sync-lots_status = api_errorflips tosuccess(N)and thatwpdeploy.lotsnow contains rows.2. On a site with no non-admin users:
do_action('auctionforge_sync_user_profile')— confirmauctionforge_last_sync-user-profile_status = idle(0)AND that wpdeploy's Sync Health page now shows a green dot for that cell.---
[3.7.0.1] — 2026-05-02
Fix: marketing data leaks WordPress admins into the people list
Why
After the 3.7.0.0 rollout the central
peopleview on wpdeploy was showing site administrators alongside real auction-house users — thesync-user-profilehandler read straight fromwp_userswith no role filter, so any account with administrator/editor/author/contributor/shop_manager capabilities was getting shipped as if it were a buyer. Marketing audiences must contain buyers, not staff.Fixes (
inc/sync/class-profile-sync.php)- The
read_batch()SQL now LEFT JOINs{$wpdb->usermeta}on the prefix-aware capabilities key ({$wpdb->prefix}capabilities) and filters out any user whose serialized capabilities meta_value containsadministrator,editor,author,contributor,shop_manager, orsuper_admin. Users withIS NULL(no roles registered) are still allowed through — those are typically subscribers/buyers on this fleet. - Watermark on
auctionforge_profile_sync_watermarkis unchanged; the next run after upgrade picks up the same batch with the new filter applied. Operationally the wpdeploy team also wiped the existing admin rows fromuser_profiles,user_interests,user_recent_activity,bids_wins, andpeopleto clear the leak server-side — total of 35 rows scrubbed.
Files Changed
- Modified:
inc/sync/class-profile-sync.php - Modified:
auctionforge.php(Version 3.7.0.0 → 3.7.0.1)
Verification on Clumber dev
1. Find a logged-in admin:
SELECT u.user_email FROM wp_users u JOIN wp_usermeta um ON um.user_id=u.ID AND um.meta_key='wp_capabilities' WHERE um.meta_value LIKE '%administrator%';2. Reset the watermark:
DELETE FROM wp_options WHERE option_name='auctionforge_profile_sync_watermark';3. Trigger sync:
do_action('auctionforge_sync_user_profile');4. On wpdeploy: confirm those admin emails do NOT appear in
user_profiles(SELECT * FROM user_profiles WHERE email='admin@…';returns zero rows).Privacy / scope
- No API contract changes. The wpdeploy
/api.php/sync-user-profileroute accepts the same payload shape; this is purely a source-side filter narrowing what gets sent.
---
[3.7.0.0] — 2026-05-02
Cross-site user data lake — full Phase 2 + Phase 3 build
Why
AuctionForge sites were exposing per-lot engagement (views, favourites, bids, wins) keyed only on the anonymous
af_vidlocalStorage hash, with no central aggregation. Marketing — even the "collect data now, send later" phase — needs a per-person view across the whole AF network: name + phone + postcode + country + IP + device fingerprint + the keywords they engage with + the bids they place + the lots they win, all rolled up across every site they've used. This release wires every piece needed for that, and keeps it sustainable: per-site aggregates rather than raw event firehose, watermarked syncs with retry, 14/30-day site-side retention, watchdog + Telegram alerts for dead streams.See
/root/.claude/plans/i-want-to-add-synthetic-goose.mdfor the full architecture.New tables (idempotent dbDelta on the existing
plugins_loadedmigration path)wp_af_stats_lot_keywords— per-lot keyword cache. Title + tags + author tokenized (lowercase → drop stop-words → drop ≤2-char → drop pure-digit), one row per (post_id, keyword). Populated onsave_post_lot.wp_af_user_interests— running tally per(user_email, dimension, dimension_value)where dimension ∈keyword | category | author | price_band. UPSERT-keyed so increments are atomic. Bounded by users × distinct interests (typically a few dozen rows per user).wp_af_user_recent_activity— capped per-user activity log (last 50 events per email). Seeds the drill-down timeline on the wpdeploy person view.wp_af_bid_events— bid + win events (auto-created by the bids sync handler). Drained and shipped to wpdeploy hourly.synced_atcolumns added towp_af_stats_pageviews,wp_af_stats_sessions,wp_af_stats_searches,wp_af_stats_outbound. Powers the durable sync-and-purge lifecycle.af_stats_db_versionbumped 2 → 3. The existingAF_Stats_Init::maybe_create_tables()picks up the new tables on the next admin page load after auto-update.
New helper classes
AF_Keyword_Extractor(inc/stats/class-keyword-extractor.php) — pure tokenizer + cache writer + read-through helper. Hookssave_post_lotto refresh on lot changes. Stop-words tunable viaapply_filters('af_keyword_stop_words', ...).AF_User_Interests(inc/stats/class-user-interests.php) —record_view / record_favorite / record_bid / record_win. All idempotent UPSERTs. CallsAF_Stats_Tracker::should_skip()first so admins/bots never pollute interest profiles.AF_Sync_Base(inc/sync/class-sync-base.php) — abstract durability backbone. Readssynced_at IS NULLbatches, POSTs, marks rows synced only on a confirmed 200, retries on next cron run if the POST fails. Idempotent UNIQUE keys on the wpdeploy side mean retries never duplicate.AF_Profile_Sync/AF_Interests_Sync/AF_Activity_Sync/AF_Lots_Sync/AF_Bids_Sync— five concrete sync streams.AF_Data_Purge(inc/maintenance/class-data-purge.php) — daily cron: 14-day floor on synced rows, 30-day hard cap with CRITICAL alert if any unsynced row hits the cap (which would mean wpdeploy has been unreachable for a month).
New cron schedules (auto-registered on plugins_loaded if
auctionforge_update_server_url+_api_keyare configured)| Hook | Schedule | Endpoint |
|---|---|---|
|
auctionforge_sync_user_profile| hourly |POST /api.php/sync-user-profile||
auctionforge_sync_user_interests| hourly |POST /api.php/sync-user-interests||
auctionforge_sync_user_activity| hourly |POST /api.php/sync-user-activity||
auctionforge_sync_lots| every 10 min |POST /api.php/sync-lots||
auctionforge_sync_bids_wins| hourly |POST /api.php/sync-bids-wins||
auctionforge_purge_synced_data| daily | (purge cron — local) |All sync handlers are watermarked or
synced_at-gated; cron mid-run failure is harmless because the next run picks up the same rows.Hooks fired
af_stats_pageview_recorded($url, $email, $visitor_hash)— fires insideAF_Stats_Ajax::handle_track()after a logged-in pageview is recorded. Default listener resolves URL → lot post →AF_User_Interests::record_view().af_stats_lot_favorited($email, $post_id)— fires from the existinglot_analytics_record_favoriteAJAX handler when a watchlist add happens. Default listener callsrecord_favorite().
Server-side companion (wpdeploy)
This release is paired with wpdeploy changes (handled out-of-band; not in the plugin zip):
- 5 new API routes matching the sync streams above. All return
synced+ watermark metadata so the plugin can advance / mark rows synced. update_sync_health()helper in wpdeploy — every successful sync POST writes(stream, last_seen_at, last_synced_count, state)intosites.sync_health_json.SyncWatchdog— 5-minute cron on wpdeploy that scans every (site × stream) cell and runs anok → overdue → gone → recovering → okstate machine. Emits alerts via the existingsync_incidentsTelegram fan-out.- People section in the wpdeploy admin —
?tab=people(cross-site rollup with top keywords / lifetime spend),?tab=person&email=...(drill-down with timeline + bids),?tab=people-export(Google Customer Match + Meta Custom Audience CSV with sha256 hashing per spec). ?tab=sync-health— site × stream traffic-light grid showing every sync's state.
Files Changed
- Created:
inc/stats/class-keyword-extractor.php,inc/stats/class-user-interests.php,inc/stats/stop-words.php - Created:
inc/sync/class-sync-base.php,inc/sync/class-profile-sync.php,inc/sync/class-interests-sync.php,inc/sync/class-activity-sync.php,inc/sync/class-lots-sync.php,inc/sync/class-bids-sync.php - Created:
inc/maintenance/class-data-purge.php - Modified:
inc/stats/class-stats-database.php(DB_VERSION = 3, new dbDelta calls, synced_at column adds) - Modified:
inc/stats/class-stats-init.php(require new classes, register sync crons, wireaf_stats_pageview_recordedandaf_stats_lot_favoritedlisteners) - Modified:
inc/stats/class-stats-ajax.php(fireaf_stats_pageview_recordedafter pageview record; fireaf_stats_lot_favoritedon watchlist add) - Modified:
auctionforge.php(Version: 3.6.4.0 → 3.7.0.0)
Verification on Clumber dev
1. After auto-update + first wp-admin page load:
wp_af_stats_lot_keywords,wp_af_user_interests,wp_af_user_recent_activityall exist;af_stats_db_version = 3.2. Save a test lot titled
"Pair of Victorian silver candlesticks by Mappin & Webb"→wp_af_stats_lot_keywordshas rows forvictorian, silver, candlesticks, mappin, webb(and notpair, of, by).3. Log in as throwaway test user, view 3 of those lots →
wp_af_user_interestsshows(test@…, keyword, 'victorian', view_count=3).4. Wait one hourly cron, confirm
wpdeploy.user_interestsmirror via the wpdeploy admin →?tab=people→ search for the test email.5. Confirm
wpdeploy.sites.sync_health_jsonhasuser-interests.state = 'ok'for the Clumber site.6. Pause the cron, wait 2h, watch the watchdog flip the cell to
overdueand emit a Telegram alert.Privacy / scope
- Admins and bots are filtered out at write time via
AF_Stats_Tracker::should_skip(). - Email is normalized lowercase + trim before storage; phone normalized to E.164 (UK-aware) on the sync side.
- No outbound activation yet — wpdeploy stores everything but doesn't send anything to anyone. Marketing send mechanics (consent flag, suppression list, sender) explicitly deferred.
---
[3.6.4.0] — 2026-05-02
Identity stitching: visitor_hash → user_email
Why
The
af_stats_*tables (pageviews,sessions,searches,outbound) and the lot-engagement tables (af_lot_analytics,af_lot_shares) currently store activity keyed only on the anonymousaf_vidlocalStorage hash — there is no link from any browsing event to the user's email even when they're logged in. Without that link, the central wpdeploy server can never aggregate behavioural data on a per-person basis, which is the prerequisite for the cross-site user-data lake being built on wpdeploy (see/root/.claude/plans/i-want-to-add-synthetic-goose.mdPhase 1).This release adds the bridge: every authenticated tracker hit records a
(visitor_hash, user_email)pair into a new table. From here on, anonymous browsing can be resolved to an email via JOIN for any session the user was logged in.Changes
- New table
wp_af_stats_visitor_emails—(visitor_hash, user_email, ip_address, first_seen, last_seen)withUNIQUE(visitor_hash, user_email)+ index onuser_email. Created viadbDeltainside the existingAF_Stats_Database::create_tables()so it ships through the standardplugins_loadedmigration path — no manual reactivation needed after auto-update. af_stats_db_versionbumped 1 → 2.AF_Stats_Init::maybe_create_tables()now compares against the newAF_Stats_Database::DB_VERSIONconstant rather than a hard-coded< 1, so future schema bumps (Phase 2 onwards) just require constant edits + new dbDelta calls.- Identity record on every authenticated tracker hit.
AF_Stats_Ajax::handle_track()now callsAF_Stats_Visitor_Email_Map::record($visitor_hash, $email, $ip)wheneveris_user_logged_in()is true. Trust boundary: the email is read server-side fromwp_get_current_user()— clients cannot assert who they are. - Defensive table-exists guard. The new helper short-circuits silently if the migration hasn't run yet on a given site (race window on the very first request after auto-update); the next request finds the table and proceeds. No fatals, no missing rows.
- Email normalised at write time — lowercase + trim +
is_email()validation before storage. Marketing audience match-rates downstream depend on consistent casing.
Files Changed
- Created:
inc/stats/class-visitor-email-map.php - Modified:
inc/stats/class-stats-database.php(DB_VERSION constant; new table; drop_tables list) - Modified:
inc/stats/class-stats-init.php(require new helper; migration check uses constant) - Modified:
inc/stats/class-stats-ajax.php(record pair inhandle_track) - Modified:
auctionforge.php(Version header bump)
Verification on Clumber dev
1. After auto-update, load any
wp-admin/*page once →wp_af_stats_visitor_emailsexists,af_stats_db_version = 2.2. Log in as a test user, browse 5 lots → exactly one row in
wp_af_stats_visitor_emailsfor that(visitor_hash, email)pair, withlast_seenupdating on each hit.3.
SELECT email FROM wp_af_stats_visitor_emails WHERE visitor_hash IN (SELECT visitor_hash FROM wp_af_stats_pageviews WHERE created_at > NOW() - INTERVAL 1 HOUR)returns the test email — proving the JOIN works.Privacy / scope
- This change writes a
(visitor_hash, email)pair to a single new table on the AF site. Nothing is sent to wpdeploy yet — the sync stream lands in Phase 2. - Anonymous (logged-out) browsing is unaffected: no row is created until the user authenticates.
- Bots are still skipped via
AF_Stats_Tracker::is_bot()before any tracking writes.
---
[3.6.3.1] — 2026-05-01
Fix: New lots never processed + Live console improvements
Why
When BidSpirit adds new lots to an auction (e.g. items 683-692), the sync pipeline correctly staged all 709 lots into
import_historybut the InsertLotsBS processing loop exited after the first batch of 500 unchanged lots, never reaching the genuinely new lots at the tail of the queue. This caused new lots to remain permanently stuck in staging — synced but never created as WordPress posts.Separately, the admin Live Console was replaying the entire log history from the beginning on every page load, and showed long silent gaps during API calls with no indication of what the worker was doing.
Fixes
- InsertLotsBS loop break condition — The stage 5 insert loop in
CatalogSyncWorker::process()andprocessDayEnded()previously broke whenupdated lots === 0, even if the batch had cleared hundreds of unchanged ("unupdated") lots from the queue. New lots with higher IDs were never reached. Now breaks only when bothupdated lotsandunupdated lotsare 0, meaning the staging queue is truly empty. - Live Console starts from current position —
consoleSinceIdwas hardcoded to0, causing the console to page through the entireaf_sync_logtable (50 rows at a time) before reaching real-time entries. Now initializes toSyncLogger::getLatestId()so only entries created after page load appear. queueIsActivedeclaration order — Variable was declared after functions that referenced it, causing the console to always start at the slow 3s polling rate even when a worker was active. Moved declaration before first use.- Progress logging during API calls —
LotList::auctionProcessing()made 2-3 BidSpirit API calls with zeroSyncLoggerentries, creating long silent gaps in the console. Added log entries for API fetch start, response received (with duration), data staged, and API errors. - Per-auction progress in bulk runs —
LotList::run()now logsProcessing auction X/Y: {id}for each auction in the bulk loop, and logs skipped auctions. processDayEndedinsert loop logging — Added batch progress logging and timeout guard matching theprocess()method pattern. Previously this loop was completely silent.
Files Changed
- Modified:
inc/sync/CatalogSyncWorker.php,inc/import/LotList.php,admin/view/sync-status.php
---
[3.6.3.0] — 2026-05-01
Public Auctions API — Token Authentication
Why
The
/wp-json/auctionforge/v1/public/auctionsendpoint added in v3.6.2.9 was publicly accessible. Since auction data should only be served to authorized aggregator sites, the endpoint now requires a valid auth token.Changes
- Token verification — The
PublicAuctionsREST endpoint now validates anX-AF-Tokenheader (or?token=query parameter) against the site's existing Webhook auth token from AuctionForge settings. - Returns
401 Unauthorizedfor missing/invalid tokens and403 Forbiddenif no auth token is configured on the site. - Uses
hash_equals()for timing-safe comparison.
Files Changed
- Modified:
auctionforge.php,inc/api/PublicAuctions.php
---
[3.6.2.9] — 2026-05-01
Public Auctions REST API Endpoint
Features
- New REST endpoint
GET /wp-json/auctionforge/v1/public/auctions— Exposes auction list data (title, date, image, state, catalog link) for consumption by the AuctionForge Hub plugin on parent/main sites. - Parameters:
type(upcoming or past, default: upcoming),limit(max results, default: 50). - Handles multi-day auctions with correct part numbers and catalog links.
- Returns auction metadata including
auction_id,source_site, andday_indexfor deduplication.
Files Changed
- Modified:
auctionforge.php,inc/coreIncludes.php - Created:
inc/api/PublicAuctions.php
---
[3.6.2.8] — 2026-04-30
Suppress alerts for transient retry conditions
Why
The "BidSpirit API returned 0 lots — catalog may not be ready yet" message is logged when the BidSpirit webhook fires before the auction catalog is fully published. The safety cron retries the job automatically and it usually succeeds on the next attempt — there's no operator action required, so a Telegram alert is just noise.
Fix
- New private helper
SyncLogger::isSuppressedFromAlerts($message, $context)matches the message against a substring allowlist of known-transient errors. When matched, the row is still inserted intoaf_sync_log(so the in-app sync console still shows the retry chain) but theauctionforge_sync_error_loggedfan-out action does NOT fire — wpdeploy and Telegram stay quiet. - Default suppression substrings:
"BidSpirit API returned 0 lots","catalog may not be ready yet". - Extendable via the new
auctionforge_sync_alert_suppress_patternsfilter — themes/MU plugins can add their own substrings.
Files Changed
- Modified:
auctionforge.php,inc/sync/SyncLogger.php
---
[3.6.2.7] — 2026-04-30
Typo fix
- Settings → Connections tab: the placeholder/help text under the Server field showed
https://my-accaunt.bidspirit.com/(extra "a"). Now readshttps://my-account.bidspirit.com/.
Files Changed
- Modified:
auctionforge.php,inc/controllers/Settings.php
---
[3.6.2.6] — 2026-04-30
Fix stale
plugin_versionin reportsWhy
Sites were reporting their old version to wpdeploy long after they'd been upgraded — e.g. Lonsdale Auctioneers ran v3.6.1.1 but kept telling wpdeploy it was on v2.9.6. Root cause: the constant
AUCTIONFORGE_VERSIONis read from the plugin file'sVersion:header *once at plugin load*, then frozen into$this->current_versionon the auto-updater instance. After a plugin upgrade replaces the file on disk, existing PHP-FPM workers keep using the cached constant value until they're recycled, so every report from those workers carries the old version.Fix
- New helper
AuctionForge_Auto_Updater::get_live_version()reads the version directly from the plugin file's header on each call (viaget_file_data()— uncached). report_health,push_sync_error_immediate, andretry_sync_errorsnow sendget_live_version()instead of the cached constant.- The pre-existing iteration through active plugins inside
report_healthalready usedget_plugin_data()per plugin, so secondary plugin entries were already accurate; only the top-levelplugin_versionfield was stale.
Files Changed
- Modified:
auctionforge.php,inc/class-auto-updater.php
---
[3.6.2.5] — 2026-04-30
Real diagnostics for plugin self-updates
Why
The wpdeploy
update_queuetable had a 46% historical failure rate, but every single failure row stored the literal string"Installation failed"— collapsing every failure mode into one opaque error with no diagnostic value. Root cause: theinstall_update()method in both clients (AF auto-updater and wpd-client) treatedPlugin_Upgrader::upgrade()as a boolean, throwing awayWP_Errorobjects and skin-emitted error messages.Fixes (
inc/class-auto-updater.phpinstall_update())- Refreshes the
update_pluginstransient before invoking the upgrader. The upgrader reads from this transient to know what version to download; if WP hasn't checked recently, the upgrader silently returns false (looking like a failure even though there's a real update queued at wpdeploy). - Distinguishes
WP_Error,false/null, and success.WP_Errorwas previously treated as truthy → reported as "completed" even on failure. Now extracts the error code and message. - Reads
Automatic_Upgrader_Skin::get_errors()to surface the real upgrader-emitted error messages. - Reads
$upgrader->resultwhich holds the finalWP_Errorfor some failure paths. - Captures PHP errors/warnings emitted during the upgrade (file-move issues, etc.) via a temporary
set_error_handler. - Detects "no update in transient" as a distinct failure cause and labels it explicitly so we know it's a transient-cache problem, not an actual install failure.
- Truncates the combined diagnostic to 1000 chars before sending.
The same fix is applied to
wpd-client.php(the WPD client plugin shipped fromclient-plugin/wpd-client.phpon the wpdeploy server).Files Changed
- Modified:
auctionforge.php,inc/class-auto-updater.php
---
[3.6.2.4] — 2026-04-30
Bulk-sync worker dispatch fix
Fixes
- The HTTP-loopback worker (
auctionforge_rest_sync_workerinauctionforge.php) had its own switch statement for job-type dispatch, distinct from the one incrontasks/syncWorker.php. The newfull_sync_upcomingandfull_sync_pastjob types were only added to the CLI worker, so the loopback path produced "Unknown job type" errors. Both switches now route those types toBulkSyncWorker::process. inc/coreIncludes.phpnowrequire_oncesBulkSyncWorker.phpso the class is available wherever sync code runs.
Files Changed
- Modified:
auctionforge.php,inc/coreIncludes.php
---
[3.6.2.3] — 2026-04-30
Fixes for end-to-end Telegram round-trip
Fixes
verify_api_keyreads the option fresh on every call (hash_equalsagainstget_option('auctionforge_update_api_key')) instead of relying on the cached$this->api_keyfrom constructor time. Different FPM workers can hold different cached values when the option drifts (e.g. via auto-heal collisions), which previously produced intermittent 401s on REST endpoints.- New REST endpoint
POST /wp-json/auctionforge/v1/sync/version— wraps the existingtrigger-installflow with a JSON response (always HTTP 200 withsuccessflag). The original endpoint returnedWP_Error('no_update', …, status: 404)when the plugin was already on the latest version, which nginx'serror_page 404directive then clobbered with a static HTML 404 page on hosts using aaPanel/BTWAF. Keeping the URL under/sync/*matches the pattern that's already proven to pass through host WAFs.
Files Changed
- Modified:
auctionforge.php,inc/class-auto-updater.php
---
[3.6.2.2] — 2026-04-29
Catalog-sync kind disambiguation
Fix
catalog_syncjobs target a single auction that may be either active or archived. Until now their alerts were always classified askind=upcoming. The classifier now resolves the auction'sauction_stateterm meta and routes:ARCHIVED/ENDED/POST_AUCTION→kind=past→ Kill + Full Past buttons- anything else (or unresolvable) →
kind=upcoming→ Kill + Full Upcoming buttons
Files Changed
- Modified:
auctionforge.php,inc/class-auto-updater.php
---
[3.6.2.1] — 2026-04-29
Telegram Sync Monitoring follow-ups
Features
- Context-aware alert buttons. Each Telegram alert now shows the action set most relevant to the failing sync: upcoming-sync errors get Kill + Full Upcoming, past-sync errors get Kill + Full Past, everything else gets Kill only. Button choice is driven by a new
kindfield classified at log-write time from the queue'sjob_type. - Plugin version in alerts + Update button. Each push now includes the live
plugin_version. wpdeploy compares it to the latestis_stable=1row in itsversionstable and only renders an Update plugin button when the site is behind. Tapping Update calls the existingPOST /wp-json/auctionforge/v1/trigger-installendpoint to force the upgrade.
Architecture
- New private helper
AuctionForge_Auto_Updater::classify_error_kind($jobId)looks up the job'sjob_typeand maps it to'upcoming'/'past'/'other'. Used by both the immediate push and the 1-min retry cron. - Outbound payloads now include
plugin_versionat the top level; wpdeploy refreshessites.plugin_versionon every/sync-errorsPOST.
Files Changed
- Modified:
auctionforge.php,inc/class-auto-updater.php
---
[3.6.2.0] — 2026-04-29
Telegram Sync Monitoring & Remote Control
Features
- Instant Telegram alerts on sync errors. Any
level='error'row written toaf_sync_logis pushed (fire-and-forget, non-blocking) to wpdeploy, which fans it out to a configured Telegram group with inline-keyboard action buttons (Kill / Full Upcoming / Full Past / Acknowledge). - Remote command surface. Any group admin can tap a button to:
- Kill sync — flips DB flags via
SyncQueue::cancelAll(), then SIGTERMs every active worker; a 5-second watchdog escalates to SIGKILL for any survivor. - Full sync upcoming — full re-import of every active auction and its lots (queued, observable, killable). Replaces the
re-sync?do=importBidSpiritUpcomingflow with a queued equivalent. - Full sync past — same, for archived auctions.
- Safety-net retry cron (
auctionforge_retry_sync_errors, every minute) re-pushes recent error rows. wpdeploy dedupes viaUNIQUE(site_id, af_log_id)so duplicates are silent.
Architecture
SyncLogger::log()now firesdo_action('auctionforge_sync_error_logged', …)onlevel='error'so any handler can react. The auto-updater listener does a 2 s non-blocking POST to/api.php/sync-errors.- New REST endpoint
POST /wp-json/auctionforge/v1/sync/cancel-all(X-API-Key auth) — runsSyncQueue::cancelAll()+ SIGTERM + watchdog. Logs every action throughSyncLogger. POST /sync/startextended with amodeparameter (upcomingdefault,pastfor archived). Bulk re-sync is now a queued job, not a synchronous block.- New job types
full_sync_upcomingandfull_sync_pastonSyncQueue, dispatched to a newBulkSyncWorkerthat wraps the existingAuctionList::init()+LotList::init($upcoming)pipeline. syncWorker.phpinstalls a SIGTERM handler that flips the in-flight job tofailedwith a "Killed by admin (SIGTERM, cleanup OK)" marker and closes the DB cleanly before exiting. Watchdog escalates to SIGKILL after 5 s grace.LotList::auctionProcessing()now heartbeats the active bulk-sync job between auctions, preventing the safety cron from auto-failing long bulk runs as stale (the 600 s threshold is unchanged).
Files Changed
- Modified:
auctionforge.php,inc/sync/SyncLogger.php,inc/sync/SyncQueue.php,inc/class-auto-updater.php,crontasks/syncWorker.php,inc/import/LotList.php - Created:
inc/sync/BulkSyncWorker.php
---
[3.6.1.6] — 2026-04-29
High-Value Lot Modes for
[bp_lot_list]Features
high_value_pastmode — Displays past auction lots ordered by their catalog estimate (estimatedPriceInt), highest first. Useful for "Top Lots" or "Highlights" sections.high_value_soldmode — Displays past sold lots ordered by their actual sold price (soldBid), highest first. Only includes genuinely sold lots (soldBid > 0) and reuses the same false-positive guard asrandom_pastto skip lots wheresoldBidwas carried over fromstartPricewithout real bidding activity.- Admin documentation updated — The Shortcodes reference page in WP Admin now lists both new modes in the
modeattribute description and includes example shortcode usage.
Architecture
- New constants
MODE_HIGH_VALUE_PASTandMODE_HIGH_VALUE_SOLDonLotsWidget. - New method
LotsWidget::getLotListHighValue($mode, $limit)builds the query, applies the past-auction tax filter, setsbp_orderbyto the relevant meta field withDESCorder, and (for the sold variant) filters out unsold-but-stale lots in PHP. - New filter hook
bp_lot_list_high_value_args_filterfor downstream customization of the WP_Query args.
Files Changed
- Modified:
inc/widgets/LotsWidget.php,inc/controllers/ShortcodesPage.php
---
[3.6.0.18] — 2026-04-25
Brevo SMS Notifications Integration
Features
- Transactional SMS via Brevo API — The plugin now sends text message alerts through the Brevo transactional SMS service, running alongside existing Firebase push notifications.
- Four Notification Types:
- New Auction Published — Broadcast SMS to all opted-in subscribers when an auction is published.
- Auction Starting Soon — Targeted SMS to users registered for an auction when it is about to start.
- Favorited Item Live Soon — Targeted SMS to users who favorited a lot when it is approaching in the auction.
- Outbid Notice — SMS sent when a user's leading bid is surpassed, with a 5-minute per-item cooldown to prevent spam.
- SMS Subscriber Database — New
af_sms_subscriberstable stores user phone numbers, country codes, and per-notification-type opt-in preferences (GDPR-ready explicit consent). - Admin Settings Tab — New "SMS Notifications" tab in Settings with:
- Brevo API Key input
- SMS Sender Name (11 char max)
- Master enable/disable toggle
- Per-notification-type on/off switches
- Test SMS widget with phone input and send button
- Live subscriber count display
- Profile SMS Preferences — Users can opt into SMS notifications directly from their profile page with phone number entry and granular notification type selection.
Architecture
- BrevoSMS Service (
inc/services/BrevoSMS.php) — cURL-based API wrapper with broadcast, targeted, and single-send methods, message builders with 160-char limit awareness, rate limiting, and comprehensive error logging. - SMSSubscriber Model (
inc/model/SMSSubscriber.php) — CRUD operations, email-to-phone resolution, opt-in filtering, and upsert logic. - Webhook Integration — SMS dispatch hooks added to
AuctionsAPI.phpmethods:leading_bid_surpassed(),item_live_soon(),auction_starts_soon(), andauctionPublishedPush().
AJAX Handlers
auctionforge_sms_save— Save SMS preferences from profile pageauctionforge_sms_load— Load SMS preferences for profile pageauctionforge_sms_test— Admin-only test SMS endpoint
Database
- New table:
af_sms_subscribers— Phone numbers, country codes, per-notification opt-ins, timestamps
Files Changed
- Modified:
auctionforge.php,inc/coreIncludes.php,inc/controllers/AuctionsAPI.php,inc/controllers/Settings.php,admin/view/settings.php,templates/parts/profile-templates.php - Created:
inc/services/BrevoSMS.php,inc/model/SMSSubscriber.php
---
[3.6.0.7] — 2026-04-14
Hotfix
Fixes
- Namespace resolution — Fixed fatal error in
wp_footercommission label hook caused by unqualifiedSettingsHelperandSettingsclass references. Now uses fully qualified namespaces.
Files Changed
- Modified:
auctionforge.php
---
[3.6.0.6] — 2026-04-14
Commission Label Override Fix
Fixes
- Theme template override compatibility — Moved the commission label JS override from the
single-lot.phptemplate intoauctionforge.phpviawp_footerhook (priority 99). Sites with theme-level template overrides (e.g.themes/*/auctionforge/single-lot.php) were not picking up the inline script. Thewp_footerapproach works universally on all single lot pages.
Files Changed
- Modified:
auctionforge.php,templates/single-lot.php
---
[3.6.0.5] — 2026-04-14
Commission Label Override
Features
- Commission Label Setting — New dropdown in Settings → Appearance allowing admins to choose between "Buyer's Premium" (default) and "Auction House Commission" as the label displayed on lot pages. This overrides the Bidspirit JS client's default label using a MutationObserver that catches asynchronously injected text.
Files Changed
- Modified:
inc/controllers/Settings.php,templates/single-lot.php
---
[3.6.0.4] — 2026-04-12
Auction Approval Modal Redesign
Changes
- Removed BidSpirit Terms of Use — The generic BidSpirit "Terms of Use" section that appeared at the top of the non-credit-card approval modal has been removed. The modal now shows only the auction house's own legal agreements managed within the plugin.
- Renamed Modal Title — Changed "Terms of conditions" to "Terms & Conditions".
- Larger Scroll Area — The Terms & Conditions scroll box is now 350px tall (up from 200px) for easier reading.
- Proportional Section Heights — Refund & Return Policy and Chargeback Waiver sections use a shorter 260px scroll box to visually distinguish them from the primary Terms & Conditions.
Files Changed
- Modified:
templates/js-chunks/approval-info.php,assets/js/app.js
---
[3.6.0.2] — 2026-04-10
Webhook Token Generator
Features
- Token Generator Widget — Added a 16-character random token generator directly below the "Webhook auth token" field on the Settings page. Includes a "Generate Token" button and a clipboard copy icon with visual feedback.
Files Changed
- Modified:
inc/controllers/Settings.php
---
[3.6.0.1] — 2026-04-10
Patch
Changes
- Version bump.
---
[3.6.0.0] — 2026-04-10
Legal Agreements for Auction Approval
Features
- Terms & Conditions — A mandatory, scrollable Terms & Conditions document is now displayed during the auction approval process. Bidders must scroll to the bottom and check an agreement box before their approval request is submitted. Always enabled.
- Refund & Return Policy — An optional, scrollable Refund & Return Policy can be enabled in Settings. When enabled, bidders must read and accept it during auction approval.
- Chargeback Waiver — An optional, scrollable Chargeback Waiver can be enabled in Settings. When enabled, bidders must read and accept it during auction approval.
- Admin Management — New "Legal Agreements" page under the Bidspirit admin menu with tabbed TinyMCE editors for each agreement type. Includes automatic version numbering (incremented on content change) and full version history.
- Consent Logging — Every agreement acceptance is logged to a dedicated database table (
af_user_agreement_log) with the agreement type, version, user email, IP address, user agent, auction ID, and timestamp. - User Tracking Integration — Agreement events (
terms_agreement,refund_agreement,chargeback_waiver) are also recorded in the existing IP tracking system alongside registration, login, and bid events. - Placeholder Content — Default sample content is seeded on plugin activation for all three agreement types.
Settings Added
- Enable Refund & Return Policy — Toggle to require bidders to accept the refund policy during auction approval.
- Enable Chargeback Waiver — Toggle to require bidders to accept the chargeback waiver during auction approval.
Database
- New table:
af_legal_agreements— Current active agreement content per type - New table:
af_legal_agreement_versions— Version history archive - New table:
af_user_agreement_log— User consent records
Files Changed
- Modified:
auctionforge.php,inc/controllers/Settings.php,inc/controllers/BidspiritViews.php,inc/ip-logger.php,templates/js-chunks/approval-info.php,assets/js/app.js - Created:
inc/legal/class-legal-agreements.php,admin/view/legal-agreements.php
---
[3.5.0.6] — 2026-04-08
Bid Event Tracking
Features
- Bid Tracking — All successful bids (regular, catalog, pre-sale buyout, post-sale purchase) now fire
afLogIP("bid", bidspiritUser)to capture the bidder's full identity in the user tracking table. - Whitelist Update — Added
bidto the allowedevent_typevalues in both the local plugin and the central WPDeploy API.
---
[3.5.0.5] — 2026-04-08
Self-Healing Database Schema
Features
- Auto-Migration — The plugin now auto-detects and adds any missing tracking table columns on version upgrade, ensuring sites with older schemas seamlessly migrate without manual SQL.
---
[3.5.0.4] — 2026-04-08
API Key Auto-Healing
Features
- Seamless Self-Registration — The WordPress plugin now autonomously regenerates and saves a fresh API Key whenever WPDeploy rejects a payload with an
api_key_collisionerror. This guarantees zero-downtime security handovers when developers clone instances to proxy/staging servers.
---
[3.5.0.3] — 2026-04-08
API Key Collision Defense
Features
- 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_collisionerrors, directly instructing developers to update cloned keys.
---
[3.5.0.2] — 2026-04-08
Modal Trigger Hotfix
Fixes
- Restructured internal UI rendering priority to gracefully deploy the inline Modal triggers inside custom IP log view without colliding with cached
z-indexstacks.
---
[3.5.0.1] — 2026-04-08
Hotfix
Fixes
- Timed Auction Badge Visibility — Fixed a strict type-matching bug in the main
auction_list.phpcore file that incorrectly hid the "Timed Auction" badge overlay from valid timed/online auctions on the main upcoming/archive views. The badge now displays properly across all manual and Bidspirit-synced objects when toggled on.
Files Changed
- Modified:
templates/main/auction_list.php
---
[3.2.9.1] — 2026-03-30
Timed Auction Display Enhancements
Features
- Timed Auction Countdown Text Toggle — Added a WP-Admin setting "Change text to 'Auction will close in'" that conditionally changes the countdown label for timed/online auctions on single lot pages.
- Shortcode Text Toggle Support — Extended the new countdown text logic to the
bp_upcoming_wideshortcodes so "Live bidding starts in:" successfully transitions to "Auction will close in:" for timed auctions.
Files Changed
- Modified:
inc/controllers/Settings.php,templates/single-lot.php,templates/shortcodes/upcoming-auction-wide.php,templates/shortcodes/upcoming-auction-wide-manual.php
---
[3.2.9.0] — 2026-03-29
Billing & Invoices Polish
Fixes
- Profile Invoice ID Tracking — Prevented internal auction codes (e.g.
002orai4) from breaking into the clean hyphenated titles inside theprofile-templates.phpview. - Dynamic Payment Statuses — Replaced Bidspirit's default/cached
NOT PAIDHTML payloads by wiring thedompdfgenerator to directly respect the current$b.statusstring from the API (resolving instances where a paid invoice still printed "NOT PAID" atop the document). - Payment Instructions Conditional — Automatically hide the "Payment Instructions" block from the PDF footer when an invoice is fully paid.
- Improved Nomenclature — Changed "Invoice No:" to "Bidder No:" on document output to prevent confusion with static invoice ledger IDs.
---
[3.2.6.0] — 2026-03-28
Multi-Day Auction Lot Filtering Fix
Fixes
- Day 2+ showing lots from Day 1 in multi-day auctions — The
itemIndexcolumn inbp_meta_dataisvarchar(55), but the day-range filter inBidspiritQuery::bp_query_where()was comparing it as a string. With string comparison, lot numbers like'11','101'–'145'incorrectly fell between'1001'and'1450', causing Day 1 lots to leak into Day 2 results. Fixed by usingCAST(bpMeta.itemIndex AS UNSIGNED)for numeric comparison andintval()on the PHP-side boundary values. Letter lots (e.g.14A,1025A) are handled correctly —CASTstrips the suffix, keeping them grouped with their base lot number.
Files Changed
- Modified:
inc/controllers/BidspiritQuery.php
---
[3.2.5.9] — 2026-03-27
Catalog Page Fix
Fixes
- Duplicate preview hours on catalog pages — The
displayHoursfield was rendered twice: once via thebp_after_description_auctionhook inBidspiritViews.phpand once inline in the auction template. Removed the hook-based rendering to eliminate the duplication.
Files Changed
- Modified:
inc/controllers/BidspiritViews.php,templates/main/auction.php
---
[3.2.5] — 2026-03-19
Sync Reliability & Stuck Lot Prevention
Fixes
- CATALOG_PUBLISHED webhook now triggers catalog sync — Previously only sent push notifications without syncing lots. When the earlier AUCTION_CATALOG_UPDATED fired before the catalog was ready on BidSpirit, lots were never imported. CATALOG_PUBLISHED now calls
auctionCatalogUpdated()to trigger a full catalog sync when the catalog is actually available. - 0-lot API results now fail instead of silently succeeding — When BidSpirit API returns 0 lots (catalog not yet ready), the sync job now fails with an explicit error message, allowing the next webhook to create a fresh retry job.
- Expanded CDN allowlist in pre_http_request filter — The HTTP filter during bulk post insertion now allows all
*.bidspirit.comsubdomains and BidSpirit image CDNs (fastly.net,cloudfront.net). Previously onlybidspirit.comandwww.bidspirit.comwere allowed, blocking image downloads during sync and causing worker hangs. - InsertLotsBS timeout guard — Stage 5 (InsertLotsBS processing loop) now has a 180-second timeout and logs progress every 2 batches. Prevents indefinite hangs that previously required manual force-kill.
- fixResult() no longer marks lots as done when postId=0 — When
lotProcessing()fails to create a WP post, the staging row now keepssyncFinished=0so the lot is retried on the next sync pass, instead of being permanently marked as complete with no actual post. - lotProcessing() logs error on missing auction term — Previously returned 0 silently when
Auction::findAuctionById()failed. Now logs an explicit error that feeds intofixResult()to keep the lot retryable. - Hourly orphan detection in safety cron — New step in
syncSafety.phpdetects lot posts that exist inbp_meta_databut are missing their auction taxonomy assignment (caused by workers killed mid-batch) and auto-repairs them withwp_set_object_terms().
Files Changed
- Modified:
inc/controllers/AuctionsAPI.php,inc/sync/CatalogSyncWorker.php,inc/abs/InsertLotsAbstract.php,inc/import/InsertLotsBS.php,crontasks/syncSafety.php
---
[3.2.4] — 2026-03-18
Sync Worker Hang Fix
Fixes
- Sync workers hanging at InsertLotsBS stage — Third-party plugins (Smush Pro, SmartCrawl SEO, WPMU DEV Updates) hook into
wp_insert_post()and make blocking outbound HTTPS calls for every lot processed. With 489+ lots per auction, this caused workers to hang indefinitely on socket reads to WPMU DEV servers (32.193.94.25,32.193.93.106). AddedWP_IMPORTINGconstant at the REST worker entry point and apre_http_requestfilter inCatalogSyncWorkerthat blocks all non-essential external HTTP during the batch post-insertion phase. Loopback (127.0.0.1,localhost) and BidSpirit API calls remain allowed. - Stuck staging rows after force-kill — When workers were force-killed mid-sync, staging rows in
import_historywere left withsyncstart=1and never unblocked. Subsequent sync runs could not see these rows (filtered out byLot::getRawLots()), causing the InsertLotsBS loop to exit immediately with 0 posts processed. Combined with job deduplication (SyncQueue::enqueue()skips if aprocessingjob exists), this created a deadlock where no new sync could proceed.
Files Changed
- Modified:
auctionforge.php,inc/sync/CatalogSyncWorker.php
---
[3.2.2] — 2026-03-17
Full Sync Auction Discovery Fix
Fixes
- Full Sync finds no auctions on fresh sites — The v3
full_syncaction only queried the WordPress database for existing auction terms, but on a freshly deployed site the database has zero auctions. AddedAuctionList::init()discovery step before querying the DB, so Full Sync now fetches all auctions from the BidSpirit API and creates taxonomy terms first, then enqueues catalog sync jobs for each.
Files Changed
- Modified:
auctionforge.php
---
[3.2.0] — 2026-03-14
Webhook Pipeline Fixes, Archive Sync & Admin UI Overhaul
New Features
- Archive Sync — New "Archive Sync" button on Sync Status admin page. Enqueues catalog sync jobs for all ARCHIVED/ENDED auctions. Past auctions now appear in the auction dropdown with an optgroup separator and state label.
- Sync Tasks v3 — Replaced old v2 task cards (importData, importBidSpirit, lotBidSpiritOld) with v3 queue-based tasks. "Sync Active Auctions" and "Sync Archived Auctions" now enqueue jobs via the queue system. Maintenance tasks (Clean Draft/Trash Lots, Clean Orphaned Meta) remain as direct-execution tasks.
- How It Works guide rewritten — Complete rewrite of the admin guide for v3 architecture. Documents webhook-first flow, all 5 job types, queue system mechanics, cron setup (external + WP-Cron), configuration constants, and troubleshooting.
Fixes
- Dual-write removed — Removed legacy handlers from
auctionCatalogUpdated(),auctionDayEnded(), anditemsUpdated()webhook methods. The old handlers were racing with the v3 worker, creating orphaned staging rows inimport_historythat were never processed. All three methods now exclusively use the v3 enqueue → spawn path. - ITEMS_UPDATED webhook — Fixed
itemsUpdated()failing to enqueue jobs. TheITEMS_UPDATEDpayload hasauctionIdnested initemsByLanguage.{lang}[0].item.auctionId, not at the top level. Added extraction logic to resolve it. - ItemUpdateWorker incomplete —
ItemUpdateWorker::process()was only callingLot::bulkSave()(staging table) without runningInsertLotsBSto process staged data into WP posts andbp_meta_data. Added the InsertLotsBS processing step with autocommit restore. Item updates now flow: stage → InsertLotsBS → WP post + meta → cache clear. - Worker spawn reliability — Changed
SyncQueue::spawnWorker()from non-blocking HTTPS to blocking HTTP loopback (http://127.0.0.1with explicitHostheader, 2s timeout). Fixes nginx 403/404 errors when HTTPS loopback hits the default vhost instead of the site's vhost. - API token constant — Plugin expects
AUCTIONFORGE_API_TOKENinwp-config.php(renamed fromUCO_API_TOKENduring the plugin rename). Documented in readme.
Database
- DB version: 22 → 23
Files Changed
- Modified:
inc/controllers/AuctionsAPI.php,inc/sync/ItemUpdateWorker.php,inc/sync/SyncQueue.php,auctionforge.php,admin/view/sync-status.php,readme.txt
---
[3.0.0] — 2025-03-14
New Feature: Webhook-First Sync Architecture (Sync v3)
Overview: Complete redesign of the BidSpirit data synchronisation pipeline. Replaces the old two-phase polling system (importBidSpirit every hour + importData every minute) with a webhook-driven job queue that processes data in near real-time.
Architecture
- 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: webhook → queue → background worker → WordPress posts. - Dual-write mode — During transition, webhooks enqueue jobs AND still run the legacy handlers. Once verified, legacy handlers can be removed cleanly.
- Job deduplication — Prevents duplicate work by checking for existing pending/processing jobs with the same auction_id + job_type.
New Components
- Job Queue System (
inc/sync/SyncQueue.php) — Priority-based FIFO queue with atomic job claiming, status tracking (pending/processing/completed/failed/skipped), worker PID tracking, and automatic stuck job recovery. - Sync Logger (
inc/sync/SyncLogger.php) — Real-time log table for admin console polling with level filtering (info/success/warning/error) and incremental cursor-based retrieval. - Catalog Sync Worker (
inc/sync/CatalogSyncWorker.php) — Processes catalog_sync, full_sync, and day_ended jobs by reusing existingLotList::singleRun()logic. - Item Update Worker (
inc/sync/ItemUpdateWorker.php) — Processes individual item_update jobs with the same logic as the webhookitemsUpdatedhandler. - Background Worker (
crontasks/syncWorker.php) — Async CLI process spawned by webhooks viaexec()or by the safety cron. Claims and processes queued jobs with a configurable timeout (default 240s). - Safety Net (
crontasks/syncSafety.php) — Hourly cron that resets stuck jobs (>10min), spawns workers for pending jobs, runs a 24-hour health check (auto-enqueues full sync if no webhooks received), and purges old data.
Admin UI
- Queue Status Dashboard — New card on Sync Status page showing pending/processing/completed/failed/skipped counts, recent jobs table with real-time refresh, worker status badge, and action buttons:
- Full Sync — Enqueues catalog sync for all active auctions
- Sync Selected — Enqueue a single auction from dropdown
- Spawn Worker — Manually trigger a background worker process
- Live Console — Dark-themed terminal console on the Sync Status page. Polls
af_sync_logevery 1.5s showing timestamped, color-coded log entries from webhooks, workers, queue operations, and the safety cron. Supports pause, clear, and auto-scroll.
Cron Changes
- Removed
importData(ran every minute — ~1,440 PHP executions/day) - Removed
importBidSpirit(ran hourly — ~24 PHP executions/day) - Added
syncSafety(runs hourly at :10 — 24 PHP executions/day) - Net effect: ~62 PHP executions/hour → 1 PHP execution/hour
- WP-Cron safety hook (
auctionforge_sync_safety) — Always-active hourly event, independent of external cron - setup.sh v3 — Updated task definitions, new
migratecommand for interactive v2→v3 transition
Database
- New table:
af_sync_queue— Job queue with status, priority, source, attempts, worker PID, timing columns - New table:
af_sync_log— Real-time log entries with context, level, auction_id, job_id - DB version: 20 → 22
Constants Added
| Constant | Default | Description |
|---|---|---|
|
AUCTIONFORGE_SYNC_WORKER_TIMEOUT| 240 | Worker process timeout in seconds ||
AUCTIONFORGE_SYNC_STALE_JOB| 600 | Seconds before a processing job is considered stuck ||
AUCTIONFORGE_SYNC_HEALTH_CHECK| 86400 | Seconds without webhook before triggering full sync ||
AUCTIONFORGE_SYNC_LOG_RETENTION| 7 | Days to keep log entries ||
AUCTIONFORGE_SYNC_QUEUE_RETENTION| 30 | Days to keep completed queue jobs ||
AUCTIONFORGE_CURL_TIMEOUT| 30 | BidSpirit API cURL timeout in seconds ||
AUCTIONFORGE_PHP_BINARY| /www/server/php/83/bin/php | PHP CLI binary path for spawning workers |AJAX Handlers Added
auctionforge_sync_log_poll— Incremental log polling for live consoleauctionforge_sync_queue_status— Queue counts + recent jobs for dashboardauctionforge_sync_enqueue— Admin-triggered sync actions (full_sync, sync_auction, spawn_worker)
Fixes
- cURL timeout — BidSpiritRequest now enforces a 30-second timeout (was unlimited/0), preventing hung connections from blocking the sync pipeline.
Files Changed
- Modified:
auctionforge.php,inc/coreIncludes.php,inc/controllers/AuctionsAPI.php,inc/BidSpiritRequest.php,admin/view/sync-status.php,crontasks/setup.sh - Created:
inc/sync/SyncQueue.php,inc/sync/SyncLogger.php,inc/sync/CatalogSyncWorker.php,inc/sync/ItemUpdateWorker.php,crontasks/syncWorker.php,crontasks/syncSafety.php
---
[2.7.3.0]
Fixes
- Various stability improvements and bug fixes.
[2.7.1.2]
Fixes
- Added missing
vatAndCommission()function inloadBid()— the sales tax display on single lot pages was never being rendered because the code to callloadTemplateforvat-and-commission-templatewas missing fromapp.js.
[2.7.1.1]
Fixes
- 2 decimal places now only appear in the bid modal (Your max bid, Total Price) via
showDecimalsflag. 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.
[2.7.0.9]
Fixes
- Fixed fatal error during plugin install/upgrade:
class-stats-database.phprequire failure.
[2.7.0.0]
New Features: Advanced Lot Analytics
- Conversion Tracking, Peak Viewing Times, Pre-Sale vs Live Comparison, Category Performance, Share Analytics, Search → View Funnel, Click-Through Tracking, CSV Export, Hot Lot Badge.
- New DB table:
af_lot_shares. New columns onaf_lot_analytics. DB version bumped to 20.
[2.6.0.0]
New Feature: Lot Analytics
- Comprehensive lot view and favorite tracking system with admin dashboard.
[2.5.0.0]
New Features
- Site Statistics System — Full website analytics built into the plugin admin.
- Recently Viewed Items — Profile page tab showing last 20 viewed lots per user.
- Run Identity Check — calls the new wpdeploy
-
v3.7.0.21 Stable May 05, 2026Download v3.7.0.21📦 9.26 MB⚙️ WP 5.2+🔧 PHP 7.2+✓ Tested 6.7
Adds Connection Diagnostics card on Lots → Updates with Run Identity Check + Re-register & Reset Kuma buttons. Detects and one-click-heals identity mismatches caused by wp_options carried over from a clone/template.
-
v3.7.0.20 Stable May 04, 2026Download v3.7.0.20📦 9.25 MB⚙️ WP 5.2+🔧 PHP 7.2+✓ Tested 6.7
Kuma heartbeat moved into the keepalive mu-plugin (v1.2.0). Site keeps reporting to Kuma even when AF is deactivated/missing or wpdeploy is offline. Adds AUCTIONFORGE_KUMA_PUSH_URL constant override for fully-decoupled operation.
-
v3.7.0.19 Stable May 04, 2026Download v3.7.0.19📦 9.25 MB⚙️ WP 5.2+🔧 PHP 7.2+✓ Tested 6.7
Reverted Kuma heartbeat cadence to bp_minutely (60s). Auto-migrates any bp_3_minutely event from 3.7.0.18 back to bp_minutely on plugin load.
-
v3.7.0.18 Stable May 04, 2026Download v3.7.0.18📦 9.25 MB⚙️ WP 5.2+🔧 PHP 7.2+✓ Tested 6.7
Kuma heartbeat cron cadence: 1 min → 3 min (new bp_3_minutely schedule). Includes auto-migration of existing scheduled events from bp_minutely on plugin upgrade. Pairs with Kuma 310s silence-detection window — single late wp-cron tick still lands inside threshold while reducing network chatter ~3x.
-
v3.7.0.17 Stable May 04, 2026Download v3.7.0.17📦 9.25 MB⚙️ WP 5.2+🔧 PHP 7.2+✓ Tested 6.4
Fix: Install Now button always returned up_to_date. The /sync/version endpoint was deleting the WP update_plugins transient then calling check_pending_updates (which hits wpdeploys /pending-updates queue endpoint, not the WP transient seed path). Transient stayed empty -> up_to_date check always tripped. Replaced with wp_update_plugins() + a belt-and-braces explicit-version-compare fallback that forces install when the request body carries a target greater than the on-disk version.
-
v3.7.0.16 Stable May 04, 2026Download v3.7.0.16📦 9.25 MB⚙️ WP 5.2+🔧 PHP 7.2+✓ Tested 6.4
Server external IP reported to wpdeploy + included in Kuma heartbeat msg as <wp_version>|<plugin_version>|<external_ip>. Plugin introspects via api.ipify.org with 24h transient cache and 3-endpoint fallback. Wpdeploy /report-health captures the IP from the payload OR falls back to REMOTE_ADDR for older plugin versions. Sites view shows the IP chip; click filters to other sites on the same physical host.
-
v3.7.0.15 Stable May 04, 2026Download v3.7.0.15📦 9.25 MB⚙️ WP 5.2+🔧 PHP 7.2+✓ Tested 6.4
New Kuma monitors land in an Unallocated group by default. Operator can drag-drop into the right group post-hoc. wpdeploy provisioner now ensures the group exists (Socket.IO add with type=group) and passes parent=<id> in subsequent monitor add payloads. Plugin code unchanged from 3.7.0.14 — clean snapshot point.
-
v3.7.0.14 Stable May 04, 2026Download v3.7.0.14📦 9.24 MB⚙️ WP 5.2+🔧 PHP 7.2+✓ Tested 6.4
Uptime Kuma push heartbeat with automatic enrolment. Each AF install becomes its own Kuma push monitor on first contact via wpdeploy provisioning a Socket.IO add as the dedicated auctionforge-bot user. Plugin-side bp_minutely cron beats every 60s with msg=<wp_version>|<af_version>; Kuma silence-detection window is 90s. Idempotency via wpdeploy.sites.kuma_monitor_id + monitor.description=wpdeploy_site_id:<id>. Notifications: existing Telegram channel auto-attached. Monitor ownership re-stamped to user_id=1 after add so admin dashboard renders the name immediately.
-
v3.7.0.13 Stable May 04, 2026Download v3.7.0.13📦 8.98 MB⚙️ WP 5.2+🔧 PHP 7.2+✓ Tested 6.4
[3.7.0.13] — 2026-05-04
Wide shortcode: hide Register button for logged-in users
- When a user is logged in to BidSpirit (
body.bp-login), the Register button is now automatically hidden on wide-format auction cards (bp_upcoming_wideandbp_auction_list layout="wide"). - The View Catalog / Catalog Coming Soon button expands to full width when the Register button is hidden.
- Uses a lightweight
MutationObserverto react to BidSpirit's async session init. - Applied to both
UpcomingAuctionWide.phpandAuctionList.phpshortcode CSS blocks.
---
- When a user is logged in to BidSpirit (
-
v3.7.0.12 Stable May 03, 2026Download v3.7.0.12📦 9.24 MB⚙️ WP 5.2+🔧 PHP 7.2+✓ Tested 6.4
Stop-word denylist for BidSpirit category-tag concatenations (uscollectibles, firearmsaccessoriesammunition, usdecorativearts, etc.). 29 known patterns added to stop-words.php so the tokenizer drops them at extraction time. New ones surfacing should be added as observed via the wpdeploy ?tab=keywords corpus page.
-
v3.7.0.11 Stable May 03, 2026Download v3.7.0.11📦 9.24 MB⚙️ WP 5.2+🔧 PHP 7.2+✓ Tested 6.4
Keyword extractor + IDF rerank — capture model years (1700-2099), hyphenated calibers (.45-70, 7.62x54r), and caliber-with-suffix (9mm, .45acp). Drop universal auction descriptors (original, marked, accessories, decorative, household, goods, made, condition, assortment). Companion wpdeploy change multiplies each keyword score by an IDF factor pulled from keyword_idf so generic words get demoted automatically and brand/maker terms rise to the top-5 chips. Reset auctionforge_lots_sync_watermark + truncate wp_af_stats_lot_keywords on each site after upgrade to force re-extraction.
-
v3.7.0.10 Stable May 03, 2026Download v3.7.0.10📦 9.24 MB⚙️ WP 5.2+🔧 PHP 7.2+✓ Tested 6.4
Lots sync — ship resolved CDN image URL via LotImage helper instead of bare BidSpirit filename. Wpdeploy was receiving "001.jpg" verbatim and the browser 404'd. Now uses LABEL_MEDIUM (~400px CDN URL) with ORIGINAL fallback and a defensive drop for anything that does not start with http(s)://. Wrapped in try/catch so a missing class or settings issue leaves image_url empty rather than failing the batch. Reset auctionforge_lots_sync_watermark on each site after upgrade to re-push existing lots through the resolver.
-
v3.7.0.9 Stable May 03, 2026Download v3.7.0.9📦 9.24 MB⚙️ WP 5.2+🔧 PHP 7.2+✓ Tested 6.4
Keepalive sweep — auto-clears WP upgrader debris (upgrade-temp-backup/, stale .maintenance, wp-content/upgrade/<plugin>-tmp/) that produce silent "Could not create directory" failures. KEEPALIVE_VERSION bumped to 1.1.0; installer rewrites the mu-plugin automatically on next AF load. Sweep is transient-guarded to once per hour with safety thresholds (.maintenance >5min, upgrade/* >60min, upgrade-temp-backup >30min) so anything in flight is left alone. Wrapped in try/catch, never blocks a request.
-
v3.7.0.8 Stable May 03, 2026Download v3.7.0.8📦 8.97 MB⚙️ WP 5.2+🔧 PHP 7.2+✓ Tested 6.4
[3.7.0.8] — 2026-05-03
Shop auction UI refinements & share button settings
Shop (Buy-It-Now) catalog improvements
- Shop sorting dropdown: Added a dedicated sorting dropdown for shop catalogs with options: Recently Added, Price: High, and Price: Low. Sorts by
buyoutPricemetadata. Regular auction catalogs retain the original sorting options. - Removed "Buyout price:" label: On shop lot pages, the redundant "Buyout price:" text before the price is now hidden. Only the price and "Buy Now" button are displayed. Regular auction buyout lots still show the label.
- Removed increments table & terms links: On shop lot pages, the "Increments table" and "Terms and conditions" links are hidden since they don't apply to buy-it-now items. The "Make an inquiry" link remains.
Buyout confirmation modal overhaul
- Sales tax logic: The buyout confirmation modal now follows the same sales tax detection as the regular bid modal. When the auction house has a US state configured, displays "Sales Tax" instead of "VAT", with the correct percentage for same-state buyers and 0% for out-of-state.
- Hide 0% buyer's premium: The Buyer's Premium line is hidden when the commission is 0%.
- Shop-specific text: For shop buyouts, all disclaimer text is replaced with: *"You will receive an email with your invoice, including shipping, and a secure payment link."*
- Shop-specific buttons: "I don't Agree" → "Cancel", "I Agree" → "Buy". The "Terms of sale" button is removed for shop buyouts. Non-shop buyouts retain the original layout.
Purchase confirmed screen
- Title changed from "Confirm purchase:" to "Purchase Confirmed".
- Thank you message updated to: *"Thank you for your order. We will confirm your order within 1-2 business days and email you an invoice, including shipping, and a secure payment link."*
Share button settings (Appearance tab)
- Added a Share Buttons section to the BidSpirit Appearance settings tab with individual checkboxes for each sharing platform: Copy Link, WhatsApp, Facebook, Telegram, X (Twitter), VK, Pinterest, and Email.
- All platforms default to enabled (shown). Unchecking a platform hides that share button on all lot pages (both shop and regular auctions).
---
- Shop sorting dropdown: Added a dedicated sorting dropdown for shop catalogs with options: Recently Added, Price: High, and Price: Low. Sorts by
-
v3.7.0.7 Stable May 02, 2026Download v3.7.0.7📦 9.24 MB⚙️ WP +🔧 PHP +
Identity stitch on bidder login — keyword interest tallying now actually fires. The keyword extractor was filling lot_keywords correctly but user_interests stayed empty because identity stitching only fired when is_user_logged_in() was true on the tracker AJAX. On these auction sites bidders authenticate via BidSpirit, never as wp_users. Fix piggybacks on the existing post-login afLogIP tracker AJAX (no auth-path intervention): JS now sends localStorage[af_vid] as visitor_hash, PHP records the stitch via AF_Stats_Visitor_Email_Map::record after the existing tracking insert, and maybe_record_lot_view falls back to the stitch map when wp_get_current_user is empty. Wrapped in try/catch so any failure can never affect the BidSpirit transaction or the existing tracking response.
-
v3.7.0.6 Stable May 02, 2026Download v3.7.0.6📦 9.23 MB⚙️ WP +🔧 PHP +
Critical fix — X-API-Key header collision with sibling SmoothByte plugins (e.g. seo-aeo-optimizer). The second plugins http_request_args filter overwrote AuctionForges X-API-Key header on every outbound API call, causing wpdeploy to 401 every sync, report-health, and check-update on affected sites. Filter is now defensive: refuses to clobber an existing X-API-Key, and for download URLs only stamps when the URL slug matches our own. Same fix applied to seo-aeo-optimizer.
-
v3.7.0.5 Stable May 02, 2026Download v3.7.0.5📦 9.23 MB⚙️ WP +🔧 PHP +
[3.7.0.5] — 2026-05-02
Sync Status admin panel — diagnostic + manual triggers in wp-admin
Why
Diagnosing sync issues used to require shell access on the site or piecing together state from wpdeploy's app.log. This release surfaces the same diagnostics inside wp-admin so a site admin (or anyone with
manage_options) can see exactly what's happening and trigger fixes in one click.Lives inside the existing Sync Status menu (
Lots → Sync Status) — appended below the existing content as a "Sync Diagnostics & Manual Controls" section, no duplicate menu entry.What's on the panel
Connection summary — plugin version,
af_stats_db_version, wpdeploy server URL, last 8 chars of API key, keepalive install state + auto-reactivation count.Sync streams table — for each of the 10 cron hooks (user-tracking, user-profile, user-interests, user-activity, lots, bids+wins, vulnerabilities, report-health, check-updates, fraud-enforcement):
- Configured schedule
- Last fired timestamp + status colour-coded (green=success, blue=idle/empty, red=error)
- Record count from last run
- Next scheduled run
- Current watermark (where applicable)
- "Fire now" button — clears doing_cron, calls
do_action($hook)synchronously, shows the result
One-shot utilities
Test wpdeploy connection— calls/api.php/infowith the site's API keyClear stuck cron lock— deletes thedoing_crontransient (the classic fix when scheduled events stop firing)Reinstall keepalive— overwritesmu-plugins/auctionforge-keepalive.phpfrom the bundled templateBackfill bids from legacy tracking— replayslast_event_type='bid'rows fromwp_auctionforge_user_trackingintowp_af_bid_eventsso the bids-wins stream picks them up. Useful for sites that have years of bid history in the legacy table but nothing in the new queueRun all due events now— clears doing_cron and fires everyauctionforge_*cron event whose timestamp is past due, in one go
Live response output panel shows the JSON returned from each action so you can see what just happened without leaving the page.
Files Changed
- Created:
inc/admin/class-sync-status-page.php - Modified:
inc/stats/class-stats-init.php(load + init the panel) - Modified:
admin/view/sync-status.php(appendAF_Sync_Status_Page::render_panel()call at the bottom) - Modified:
auctionforge.php(Version 3.7.0.4 → 3.7.0.5)
Verification
Navigate to Lots → Sync Status in wp-admin on any 3.7.0.5 site. Scroll past the existing content to the new "Sync Diagnostics & Manual Controls" section. Click "Test wpdeploy connection" — you should see
{"success": true, "auth_type": "site"}. Click "Fire now" on any stream — the row's last-fired timestamp should refresh after 1–2 seconds. -
v3.7.0.4 Stable May 02, 2026Download v3.7.0.4📦 9.23 MB⚙️ WP +🔧 PHP +
[3.7.0.4] — 2026-05-02
Self-healing: failed plugin updates can no longer take a site offline
Why
WordPress's plugin updater isn't transactional — when an update fails partway (corrupt unzip, fatal during the new version's
plugins_loaded, disk pressure, theme conflict, etc.) WP often deactivates the plugin and leaves the site without it. Once AuctionForge is dropped fromactive_plugins, no AF code runs again — including its sync handlers — until someone notices and reactivates manually. On the AuctionForge site fleet, this had quietly happened to ~5 sites we found; almost certainly more on production sites we don't have filesystem access to.This release ships an autonomous watchdog that lives outside the AuctionForge plugin entirely so it survives even when AF gets knocked out.
What changed
1. Self-installing keepalive (mu-plugin)
inc/keepalive/auctionforge-keepalive.template.php— a 50-line WordPress must-use plugin. Lives inwp-content/mu-plugins/, which WordPress can't deactivate. On everyplugins_loaded(priority 1, before any regular plugin), it checks: isauctionforge/auctionforge.phpon disk but missing fromactive_plugins? If yes AND the file has a validPlugin Name:header (smoke check — don't reactivate a corrupt zip), it re-adds AF andincludes the file in the same request.inc/keepalive/class-keepalive-installer.php— runs on every successful AF load. Copies the template intowp-content/mu-plugins/auctionforge-keepalive.phpif missing or version-bumped. Idempotent: comparesKEEPALIVE_VERSIONheaders, only writes on change. Refuses to overwrite a foreign mu-plugin (defensive against name collisions). Failure is non-fatal — install errors are recorded inwp_optionsfor wpdeploy visibility but never throw.
Net effect. Any site that successfully loads AF 3.7.0.4 or later will have the keepalive permanently installed in mu-plugins. From that point forward, even if a future update hard-fails, the keepalive recovers AF on the next pageview without any manual intervention or filesystem access. Crucially: this works on sites we don't own — the keepalive ships inside the AF zip, gets installed during the first successful update, and lives in mu-plugins thereafter.
2. Forensic markers
The keepalive writes three options on each recovery:
auctionforge_auto_reactivated_at— most recent recovery timestampauctionforge_auto_reactivated_count— total recoveriesauctionforge_auto_reactivated_failed_at— set when the keepalive saw AF on disk but with no Plugin Name header (genuinely corrupt — needs operator attention)
These get picked up by the AF sync streams and surfaced on the wpdeploy dashboard so you can see which sites have been quietly recovering themselves and whether a particular release is failing more than it should.
3. Companion: post-update-silence alerts on wpdeploy (server side)
Wpdeploy's
report-healthroute now compares incomingplugin_versionagainst the row and writeslast_version_changed_at+previous_plugin_versionon change. TheSyncWatchdogcron then alerts if a site has reported a version change but not sent any heartbeat for 2+ hours since — likely a failed install. Emitssync_incidentsrows withkind=post_update_failureso the existing Telegram fan-out picks them up. Each version-change event alerts at most once.Files Changed
- Created:
inc/keepalive/auctionforge-keepalive.template.php,inc/keepalive/class-keepalive-installer.php - Modified:
inc/stats/class-stats-init.php(callAF_Keepalive_Installer::maybe_install()on every plugin load) - Modified:
auctionforge.php(Version 3.7.0.3 → 3.7.0.4)
Companion server-side changes (already deployed on wpdeploy.smoothbyteit.dev — not in this zip):
sitestable:last_version_changed_at TIMESTAMP NULL,previous_plugin_version VARCHAR(20) NULLapi.php/report-health route detects version changesSyncWatchdog::maybe_alert_post_update_failure()emits the new alert kind
Verification
1. Drop a 3.7.0.4 install on any site. Confirm
wp-content/mu-plugins/auctionforge-keepalive.phpexists post-load.2. Manually deactivate AF from the database (
DELETE FROM wp_options ...active_plugins...). Hit the homepage. AF reappears inactive_plugins;auctionforge_auto_reactivated_countincrements.3. Delete
mu-plugins/auctionforge-keepalive.php. Trigger AF load (any pageview). The file reappears.4. Bump KEEPALIVE_VERSION in the source template, ship a new release, observe the installed mu-plugin update on next AF load.
Operator notes
- Sites currently in the broken state (AF deactivated, no keepalive yet) are NOT auto-rescued by this release — they need a one-time manual reactivation in wp-admin OR a fresh AF install via wp-admin's Upload Plugin. After that, the keepalive is in place and future failures self-heal.
- The post-update-failure alert won't fire for upgrades that happened before this release (no
last_version_changed_atwas recorded). It activates from the first version change wpdeploy sees from each site after this update lands.
-
v3.7.0.3 Stable May 02, 2026Download v3.7.0.3📦 9.22 MB⚙️ WP +🔧 PHP +
[3.7.0.3] — 2026-05-02
Fix: profile re-sync on login / profile-edit / register (no more empty names)
Why
The hourly profile sync uses a
user_registeredwatermark — once a user has been pushed once, the watermark advances past them and they're never re-pulled. That meant:1. Existing users whose first_name/last_name became populated AFTER their first sync stayed empty on wpdeploy forever.
2. BidSpirit-driven sites that don't write WP's standard
first_name/last_namefields shipped empty rows even though the canonical name was visible indisplay_name.The People view was showing
—for the name on rows that absolutely had a name available — just not where the sync handler was looking.Fixes (
inc/sync/class-profile-sync.php+inc/stats/class-stats-init.php)AF_Profile_Sync::push_for_user_id($user_id, $blocking=false)— new public method that builds a single user's profile row, normalises it, and POSTs to wpdeploy bypassing the watermark. Non-blocking by default (wp_remote_postwithblocking=false, timeout=2s) so login latency is unaffected.build_user_row($user_id)extracted as a reusable helper. Both the hourly batch and the on-demand push call it. Centralises role-filtering + display_name fallback + usermeta probing.display_namefallback. Whenwp_usermeta.first_name/last_nameare both empty (typical on BidSpirit-only sites),build_user_row()parsesdisplay_name("John Smith" → first=John, last=Smith) so we don't ship a row with a blank name when the data is sitting on the user record itself.- Three new action hooks registered in
class-stats-init.php::init(): wp_login→push_for_user_id($user->ID)— every login refreshes the rowprofile_update→ same — profile edits in wp-admin refreshuser_register→ same — new registrations get pushed instantly (instead of waiting up to 60 min for the next cron tick)
Files Changed
- Modified:
inc/sync/class-profile-sync.php(refactor + new method + display_name fallback) - Modified:
inc/stats/class-stats-init.php(three new action hooks) - Modified:
auctionforge.php(Version 3.7.0.2 → 3.7.0.3)
Verification
1. On a 3.7.0.3 site, find a user whose
wpdeploy.user_profiles.first_nameis empty:SELECT site_id, email, first_name FROM user_profiles WHERE email='something@example.com'2. Log in as that user (or have them log in).
3. Within ~2 seconds, re-query —
first_nameshould now be populated, either from the standard meta key OR parsed fromdisplay_name.4. The non-blocking POST means the user's login experience is unchanged — no spinner, no extra latency.
Operator note
Existing wpdeploy rows with empty
first_name/last_namewill refresh automatically as users log in or edit their profile. To force a one-shot re-walk of every user on a site (regardless of watermark), reset the watermark there:DELETE FROM wp_options WHERE option_name='auctionforge_profile_sync_watermark';Next hourly cron will re-pull every non-admin user with the new fallback applied.
-
v3.7.0.2 Stable May 02, 2026Download v3.7.0.2📦 9.22 MB⚙️ WP +🔧 PHP +
[3.7.0.2] — 2026-05-02
Fix: sync-lots datetime mismatch + idle syncs now heartbeat
Why
Two issues surfaced in the wpdeploy Sync Health dashboard:
1. Every site's
sync-lotswas stuck onapi_error. The plugin sendslast_modifiedstraight fromwp_bp_meta_data.lastUpdate, which is a Unix epoch string ("1756919754"). wpdeploy'slots.last_modifiedcolumn is aDATETIME, so MariaDB rejects the insert withSQLSTATE[22007]: Incorrect datetime value. The handler recordsapi_errorand the watermark never advances, so every cron tick re-fails on the same batch.2. Sites with nothing to sync looked dead. When a sync handler had an empty batch (e.g. no non-admin users yet) it was returning early without POSTing anything. wpdeploy's
update_sync_health()only fires on a successful POST, sosites.sync_health_jsonstayed NULL and the dashboard showed grey dots — indistinguishable from a broken cron. WP-Cron was actually firing fine; the watchdog just couldn't tell.Fixes
inc/sync/class-lots-sync.php— newepoch_to_datetime()helper converts the BidSpirit epoch field to UTCY-m-d H:i:sbefore shipping. Idempotent: already-formatted datetimes pass through untouched, invalid values becomeNULL.inc/sync/class-sync-base.php::run()— always POST, even when the batch is empty. Empty payload is{records: []}and wpdeploy's existing handlers handle it gracefully (loop is skipped,update_sync_health()still fires withsynced=0). This makes the dashboard reflect cron liveness, not just data flow.
Files Changed
- Modified:
inc/sync/class-lots-sync.php - Modified:
inc/sync/class-sync-base.php - Modified:
auctionforge.php(Version 3.7.0.1 → 3.7.0.2)
Verification
1. On Clumber:
do_action('auctionforge_sync_lots')— confirm the previousauctionforge_last_sync-lots_status = api_errorflips tosuccess(N)and thatwpdeploy.lotsnow contains rows.2. On a site with no non-admin users:
do_action('auctionforge_sync_user_profile')— confirmauctionforge_last_sync-user-profile_status = idle(0)AND that wpdeploy's Sync Health page now shows a green dot for that cell. -
v3.7.0.1 Beta May 02, 2026Download v3.7.0.1📦 9.22 MB⚙️ WP +🔧 PHP +
[3.7.0.1] — 2026-05-02
Fix: marketing data leaks WordPress admins into the people list
Why
After the 3.7.0.0 rollout the central
peopleview on wpdeploy was showing site administrators alongside real auction-house users — thesync-user-profilehandler read straight fromwp_userswith no role filter, so any account with administrator/editor/author/contributor/shop_manager capabilities was getting shipped as if it were a buyer. Marketing audiences must contain buyers, not staff.Fixes (
inc/sync/class-profile-sync.php)- The
read_batch()SQL now LEFT JOINs{$wpdb->usermeta}on the prefix-aware capabilities key ({$wpdb->prefix}capabilities) and filters out any user whose serialized capabilities meta_value containsadministrator,editor,author,contributor,shop_manager, orsuper_admin. Users withIS NULL(no roles registered) are still allowed through — those are typically subscribers/buyers on this fleet. - Watermark on
auctionforge_profile_sync_watermarkis unchanged; the next run after upgrade picks up the same batch with the new filter applied. Operationally the wpdeploy team also wiped the existing admin rows fromuser_profiles,user_interests,user_recent_activity,bids_wins, andpeopleto clear the leak server-side — total of 35 rows scrubbed.
Files Changed
- Modified:
inc/sync/class-profile-sync.php - Modified:
auctionforge.php(Version 3.7.0.0 → 3.7.0.1)
Verification on Clumber dev
1. Find a logged-in admin:
SELECT u.user_email FROM wp_users u JOIN wp_usermeta um ON um.user_id=u.ID AND um.meta_key='wp_capabilities' WHERE um.meta_value LIKE '%administrator%';2. Reset the watermark:
DELETE FROM wp_options WHERE option_name='auctionforge_profile_sync_watermark';3. Trigger sync:
do_action('auctionforge_sync_user_profile');4. On wpdeploy: confirm those admin emails do NOT appear in
user_profiles(SELECT * FROM user_profiles WHERE email='admin@…';returns zero rows).Privacy / scope
- No API contract changes. The wpdeploy
/api.php/sync-user-profileroute accepts the same payload shape; this is purely a source-side filter narrowing what gets sent.
- The
-
v3.7.0.0 Beta May 02, 2026Download v3.7.0.0📦 9.22 MB⚙️ WP +🔧 PHP +
[3.7.0.0] — 2026-05-02
Cross-site user data lake — full Phase 2 + Phase 3 build
Why
AuctionForge sites were exposing per-lot engagement (views, favourites, bids, wins) keyed only on the anonymous
af_vidlocalStorage hash, with no central aggregation. Marketing — even the "collect data now, send later" phase — needs a per-person view across the whole AF network: name + phone + postcode + country + IP + device fingerprint + the keywords they engage with + the bids they place + the lots they win, all rolled up across every site they've used. This release wires every piece needed for that, and keeps it sustainable: per-site aggregates rather than raw event firehose, watermarked syncs with retry, 14/30-day site-side retention, watchdog + Telegram alerts for dead streams.See
/root/.claude/plans/i-want-to-add-synthetic-goose.mdfor the full architecture.New tables (idempotent dbDelta on the existing
plugins_loadedmigration path)wp_af_stats_lot_keywords— per-lot keyword cache. Title + tags + author tokenized (lowercase → drop stop-words → drop ≤2-char → drop pure-digit), one row per (post_id, keyword). Populated onsave_post_lot.wp_af_user_interests— running tally per(user_email, dimension, dimension_value)where dimension ∈keyword | category | author | price_band. UPSERT-keyed so increments are atomic. Bounded by users × distinct interests (typically a few dozen rows per user).wp_af_user_recent_activity— capped per-user activity log (last 50 events per email). Seeds the drill-down timeline on the wpdeploy person view.wp_af_bid_events— bid + win events (auto-created by the bids sync handler). Drained and shipped to wpdeploy hourly.synced_atcolumns added towp_af_stats_pageviews,wp_af_stats_sessions,wp_af_stats_searches,wp_af_stats_outbound. Powers the durable sync-and-purge lifecycle.af_stats_db_versionbumped 2 → 3. The existingAF_Stats_Init::maybe_create_tables()picks up the new tables on the next admin page load after auto-update.
New helper classes
AF_Keyword_Extractor(inc/stats/class-keyword-extractor.php) — pure tokenizer + cache writer + read-through helper. Hookssave_post_lotto refresh on lot changes. Stop-words tunable viaapply_filters('af_keyword_stop_words', ...).AF_User_Interests(inc/stats/class-user-interests.php) —record_view / record_favorite / record_bid / record_win. All idempotent UPSERTs. CallsAF_Stats_Tracker::should_skip()first so admins/bots never pollute interest profiles.AF_Sync_Base(inc/sync/class-sync-base.php) — abstract durability backbone. Readssynced_at IS NULLbatches, POSTs, marks rows synced only on a confirmed 200, retries on next cron run if the POST fails. Idempotent UNIQUE keys on the wpdeploy side mean retries never duplicate.AF_Profile_Sync/AF_Interests_Sync/AF_Activity_Sync/AF_Lots_Sync/AF_Bids_Sync— five concrete sync streams.AF_Data_Purge(inc/maintenance/class-data-purge.php) — daily cron: 14-day floor on synced rows, 30-day hard cap with CRITICAL alert if any unsynced row hits the cap (which would mean wpdeploy has been unreachable for a month).
New cron schedules (auto-registered on plugins_loaded if
auctionforge_update_server_url+_api_keyare configured)| Hook | Schedule | Endpoint |
|---|---|---|
|
auctionforge_sync_user_profile| hourly |POST /api.php/sync-user-profile||
auctionforge_sync_user_interests| hourly |POST /api.php/sync-user-interests||
auctionforge_sync_user_activity| hourly |POST /api.php/sync-user-activity||
auctionforge_sync_lots| every 10 min |POST /api.php/sync-lots||
auctionforge_sync_bids_wins| hourly |POST /api.php/sync-bids-wins||
auctionforge_purge_synced_data| daily | (purge cron — local) |All sync handlers are watermarked or
synced_at-gated; cron mid-run failure is harmless because the next run picks up the same rows.Hooks fired
af_stats_pageview_recorded($url, $email, $visitor_hash)— fires insideAF_Stats_Ajax::handle_track()after a logged-in pageview is recorded. Default listener resolves URL → lot post →AF_User_Interests::record_view().af_stats_lot_favorited($email, $post_id)— fires from the existinglot_analytics_record_favoriteAJAX handler when a watchlist add happens. Default listener callsrecord_favorite().
Server-side companion (wpdeploy)
This release is paired with wpdeploy changes (handled out-of-band; not in the plugin zip):
- 5 new API routes matching the sync streams above. All return
synced+ watermark metadata so the plugin can advance / mark rows synced. update_sync_health()helper in wpdeploy — every successful sync POST writes(stream, last_seen_at, last_synced_count, state)intosites.sync_health_json.SyncWatchdog— 5-minute cron on wpdeploy that scans every (site × stream) cell and runs anok → overdue → gone → recovering → okstate machine. Emits alerts via the existingsync_incidentsTelegram fan-out.- People section in the wpdeploy admin —
?tab=people(cross-site rollup with top keywords / lifetime spend),?tab=person&email=...(drill-down with timeline + bids),?tab=people-export(Google Customer Match + Meta Custom Audience CSV with sha256 hashing per spec). ?tab=sync-health— site × stream traffic-light grid showing every sync's state.
Files Changed
- Created:
inc/stats/class-keyword-extractor.php,inc/stats/class-user-interests.php,inc/stats/stop-words.php - Created:
inc/sync/class-sync-base.php,inc/sync/class-profile-sync.php,inc/sync/class-interests-sync.php,inc/sync/class-activity-sync.php,inc/sync/class-lots-sync.php,inc/sync/class-bids-sync.php - Created:
inc/maintenance/class-data-purge.php - Modified:
inc/stats/class-stats-database.php(DB_VERSION = 3, new dbDelta calls, synced_at column adds) - Modified:
inc/stats/class-stats-init.php(require new classes, register sync crons, wireaf_stats_pageview_recordedandaf_stats_lot_favoritedlisteners) - Modified:
inc/stats/class-stats-ajax.php(fireaf_stats_pageview_recordedafter pageview record; fireaf_stats_lot_favoritedon watchlist add) - Modified:
auctionforge.php(Version: 3.6.4.0 → 3.7.0.0)
Verification on Clumber dev
1. After auto-update + first wp-admin page load:
wp_af_stats_lot_keywords,wp_af_user_interests,wp_af_user_recent_activityall exist;af_stats_db_version = 3.2. Save a test lot titled
"Pair of Victorian silver candlesticks by Mappin & Webb"→wp_af_stats_lot_keywordshas rows forvictorian, silver, candlesticks, mappin, webb(and notpair, of, by).3. Log in as throwaway test user, view 3 of those lots →
wp_af_user_interestsshows(test@…, keyword, 'victorian', view_count=3).4. Wait one hourly cron, confirm
wpdeploy.user_interestsmirror via the wpdeploy admin →?tab=people→ search for the test email.5. Confirm
wpdeploy.sites.sync_health_jsonhasuser-interests.state = 'ok'for the Clumber site.6. Pause the cron, wait 2h, watch the watchdog flip the cell to
overdueand emit a Telegram alert.Privacy / scope
- Admins and bots are filtered out at write time via
AF_Stats_Tracker::should_skip(). - Email is normalized lowercase + trim before storage; phone normalized to E.164 (UK-aware) on the sync side.
- No outbound activation yet — wpdeploy stores everything but doesn't send anything to anyone. Marketing send mechanics (consent flag, suppression list, sender) explicitly deferred.
-
v3.6.3.2 Stable May 01, 2026Download v3.6.3.2📦 8.93 MB⚙️ WP 5.2+🔧 PHP 7.2+✓ Tested 6.4
AuctionForge Changelog
All notable changes to the AuctionForge plugin are documented in this file.
---
[3.6.3.1] — 2026-05-01
Fix: New lots never processed + Live console improvements
Why
When BidSpirit adds new lots to an auction (e.g. items 683-692), the sync pipeline correctly staged all 709 lots into
import_historybut the InsertLotsBS processing loop exited after the first batch of 500 unchanged lots, never reaching the genuinely new lots at the tail of the queue. This caused new lots to remain permanently stuck in staging — synced but never created as WordPress posts.Separately, the admin Live Console was replaying the entire log history from the beginning on every page load, and showed long silent gaps during API calls with no indication of what the worker was doing.
Fixes
- InsertLotsBS loop break condition — The stage 5 insert loop in
CatalogSyncWorker::process()andprocessDayEnded()previously broke whenupdated lots === 0, even if the batch had cleared hundreds of unchanged ("unupdated") lots from the queue. New lots with higher IDs were never reached. Now breaks only when bothupdated lotsandunupdated lotsare 0, meaning the staging queue is truly empty. - Live Console starts from current position —
consoleSinceIdwas hardcoded to0, causing the console to page through the entireaf_sync_logtable (50 rows at a time) before reaching real-time entries. Now initializes toSyncLogger::getLatestId()so only entries created after page load appear. queueIsActivedeclaration order — Variable was declared after functions that referenced it, causing the console to always start at the slow 3s polling rate even when a worker was active. Moved declaration before first use.- Progress logging during API calls —
LotList::auctionProcessing()made 2-3 BidSpirit API calls with zeroSyncLoggerentries, creating long silent gaps in the console. Added log entries for API fetch start, response received (with duration), data staged, and API errors. - Per-auction progress in bulk runs —
LotList::run()now logsProcessing auction X/Y: {id}for each auction in the bulk loop, and logs skipped auctions. processDayEndedinsert loop logging — Added batch progress logging and timeout guard matching theprocess()method pattern. Previously this loop was completely silent.
Files Changed
- Modified:
inc/sync/CatalogSyncWorker.php,inc/import/LotList.php,admin/view/sync-status.php
---
[3.6.3.0] — 2026-05-01
Public Auctions API — Token Authentication
Why
The
/wp-json/auctionforge/v1/public/auctionsendpoint added in v3.6.2.9 was publicly accessible. Since auction data should only be served to authorized aggregator sites, the endpoint now requires a valid auth token.Changes
- Token verification — The
PublicAuctionsREST endpoint now validates anX-AF-Tokenheader (or?token=query parameter) against the site's existing Webhook auth token from AuctionForge settings. - Returns
401 Unauthorizedfor missing/invalid tokens and403 Forbiddenif no auth token is configured on the site. - Uses
hash_equals()for timing-safe comparison.
Files Changed
- Modified:
auctionforge.php,inc/api/PublicAuctions.php
---
[3.6.2.9] — 2026-05-01
Public Auctions REST API Endpoint
Features
- New REST endpoint
GET /wp-json/auctionforge/v1/public/auctions— Exposes auction list data (title, date, image, state, catalog link) for consumption by the AuctionForge Hub plugin on parent/main sites. - Parameters:
type(upcoming or past, default: upcoming),limit(max results, default: 50). - Handles multi-day auctions with correct part numbers and catalog links.
- Returns auction metadata including
auction_id,source_site, andday_indexfor deduplication.
Files Changed
- Modified:
auctionforge.php,inc/coreIncludes.php - Created:
inc/api/PublicAuctions.php
---
[3.6.2.8] — 2026-04-30
Suppress alerts for transient retry conditions
Why
The "BidSpirit API returned 0 lots — catalog may not be ready yet" message is logged when the BidSpirit webhook fires before the auction catalog is fully published. The safety cron retries the job automatically and it usually succeeds on the next attempt — there's no operator action required, so a Telegram alert is just noise.
Fix
- New private helper
SyncLogger::isSuppressedFromAlerts($message, $context)matches the message against a substring allowlist of known-transient errors. When matched, the row is still inserted intoaf_sync_log(so the in-app sync console still shows the retry chain) but theauctionforge_sync_error_loggedfan-out action does NOT fire — wpdeploy and Telegram stay quiet. - Default suppression substrings:
"BidSpirit API returned 0 lots","catalog may not be ready yet". - Extendable via the new
auctionforge_sync_alert_suppress_patternsfilter — themes/MU plugins can add their own substrings.
Files Changed
- Modified:
auctionforge.php,inc/sync/SyncLogger.php
---
[3.6.2.7] — 2026-04-30
Typo fix
- Settings → Connections tab: the placeholder/help text under the Server field showed
https://my-accaunt.bidspirit.com/(extra "a"). Now readshttps://my-account.bidspirit.com/.
Files Changed
- Modified:
auctionforge.php,inc/controllers/Settings.php
---
[3.6.2.6] — 2026-04-30
Fix stale
plugin_versionin reportsWhy
Sites were reporting their old version to wpdeploy long after they'd been upgraded — e.g. Lonsdale Auctioneers ran v3.6.1.1 but kept telling wpdeploy it was on v2.9.6. Root cause: the constant
AUCTIONFORGE_VERSIONis read from the plugin file'sVersion:header *once at plugin load*, then frozen into$this->current_versionon the auto-updater instance. After a plugin upgrade replaces the file on disk, existing PHP-FPM workers keep using the cached constant value until they're recycled, so every report from those workers carries the old version.Fix
- New helper
AuctionForge_Auto_Updater::get_live_version()reads the version directly from the plugin file's header on each call (viaget_file_data()— uncached). report_health,push_sync_error_immediate, andretry_sync_errorsnow sendget_live_version()instead of the cached constant.- The pre-existing iteration through active plugins inside
report_healthalready usedget_plugin_data()per plugin, so secondary plugin entries were already accurate; only the top-levelplugin_versionfield was stale.
Files Changed
- Modified:
auctionforge.php,inc/class-auto-updater.php
---
[3.6.2.5] — 2026-04-30
Real diagnostics for plugin self-updates
Why
The wpdeploy
update_queuetable had a 46% historical failure rate, but every single failure row stored the literal string"Installation failed"— collapsing every failure mode into one opaque error with no diagnostic value. Root cause: theinstall_update()method in both clients (AF auto-updater and wpd-client) treatedPlugin_Upgrader::upgrade()as a boolean, throwing awayWP_Errorobjects and skin-emitted error messages.Fixes (
inc/class-auto-updater.phpinstall_update())- Refreshes the
update_pluginstransient before invoking the upgrader. The upgrader reads from this transient to know what version to download; if WP hasn't checked recently, the upgrader silently returns false (looking like a failure even though there's a real update queued at wpdeploy). - Distinguishes
WP_Error,false/null, and success.WP_Errorwas previously treated as truthy → reported as "completed" even on failure. Now extracts the error code and message. - Reads
Automatic_Upgrader_Skin::get_errors()to surface the real upgrader-emitted error messages. - Reads
$upgrader->resultwhich holds the finalWP_Errorfor some failure paths. - Captures PHP errors/warnings emitted during the upgrade (file-move issues, etc.) via a temporary
set_error_handler. - Detects "no update in transient" as a distinct failure cause and labels it explicitly so we know it's a transient-cache problem, not an actual install failure.
- Truncates the combined diagnostic to 1000 chars before sending.
The same fix is applied to
wpd-client.php(the WPD client plugin shipped fromclient-plugin/wpd-client.phpon the wpdeploy server).Files Changed
- Modified:
auctionforge.php,inc/class-auto-updater.php
---
[3.6.2.4] — 2026-04-30
Bulk-sync worker dispatch fix
Fixes
- The HTTP-loopback worker (
auctionforge_rest_sync_workerinauctionforge.php) had its own switch statement for job-type dispatch, distinct from the one incrontasks/syncWorker.php. The newfull_sync_upcomingandfull_sync_pastjob types were only added to the CLI worker, so the loopback path produced "Unknown job type" errors. Both switches now route those types toBulkSyncWorker::process. inc/coreIncludes.phpnowrequire_oncesBulkSyncWorker.phpso the class is available wherever sync code runs.
Files Changed
- Modified:
auctionforge.php,inc/coreIncludes.php
---
[3.6.2.3] — 2026-04-30
Fixes for end-to-end Telegram round-trip
Fixes
verify_api_keyreads the option fresh on every call (hash_equalsagainstget_option('auctionforge_update_api_key')) instead of relying on the cached$this->api_keyfrom constructor time. Different FPM workers can hold different cached values when the option drifts (e.g. via auto-heal collisions), which previously produced intermittent 401s on REST endpoints.- New REST endpoint
POST /wp-json/auctionforge/v1/sync/version— wraps the existingtrigger-installflow with a JSON response (always HTTP 200 withsuccessflag). The original endpoint returnedWP_Error('no_update', …, status: 404)when the plugin was already on the latest version, which nginx'serror_page 404directive then clobbered with a static HTML 404 page on hosts using aaPanel/BTWAF. Keeping the URL under/sync/*matches the pattern that's already proven to pass through host WAFs.
Files Changed
- Modified:
auctionforge.php,inc/class-auto-updater.php
---
[3.6.2.2] — 2026-04-29
Catalog-sync kind disambiguation
Fix
catalog_syncjobs target a single auction that may be either active or archived. Until now their alerts were always classified askind=upcoming. The classifier now resolves the auction'sauction_stateterm meta and routes:ARCHIVED/ENDED/POST_AUCTION→kind=past→ Kill + Full Past buttons- anything else (or unresolvable) →
kind=upcoming→ Kill + Full Upcoming buttons
Files Changed
- Modified:
auctionforge.php,inc/class-auto-updater.php
---
[3.6.2.1] — 2026-04-29
Telegram Sync Monitoring follow-ups
Features
- Context-aware alert buttons. Each Telegram alert now shows the action set most relevant to the failing sync: upcoming-sync errors get Kill + Full Upcoming, past-sync errors get Kill + Full Past, everything else gets Kill only. Button choice is driven by a new
kindfield classified at log-write time from the queue'sjob_type. - Plugin version in alerts + Update button. Each push now includes the live
plugin_version. wpdeploy compares it to the latestis_stable=1row in itsversionstable and only renders an Update plugin button when the site is behind. Tapping Update calls the existingPOST /wp-json/auctionforge/v1/trigger-installendpoint to force the upgrade.
Architecture
- New private helper
AuctionForge_Auto_Updater::classify_error_kind($jobId)looks up the job'sjob_typeand maps it to'upcoming'/'past'/'other'. Used by both the immediate push and the 1-min retry cron. - Outbound payloads now include
plugin_versionat the top level; wpdeploy refreshessites.plugin_versionon every/sync-errorsPOST.
Files Changed
- Modified:
auctionforge.php,inc/class-auto-updater.php
---
[3.6.2.0] — 2026-04-29
Telegram Sync Monitoring & Remote Control
Features
- Instant Telegram alerts on sync errors. Any
level='error'row written toaf_sync_logis pushed (fire-and-forget, non-blocking) to wpdeploy, which fans it out to a configured Telegram group with inline-keyboard action buttons (Kill / Full Upcoming / Full Past / Acknowledge). - Remote command surface. Any group admin can tap a button to:
- Kill sync — flips DB flags via
SyncQueue::cancelAll(), then SIGTERMs every active worker; a 5-second watchdog escalates to SIGKILL for any survivor. - Full sync upcoming — full re-import of every active auction and its lots (queued, observable, killable). Replaces the
re-sync?do=importBidSpiritUpcomingflow with a queued equivalent. - Full sync past — same, for archived auctions.
- Safety-net retry cron (
auctionforge_retry_sync_errors, every minute) re-pushes recent error rows. wpdeploy dedupes viaUNIQUE(site_id, af_log_id)so duplicates are silent.
Architecture
SyncLogger::log()now firesdo_action('auctionforge_sync_error_logged', …)onlevel='error'so any handler can react. The auto-updater listener does a 2 s non-blocking POST to/api.php/sync-errors.- New REST endpoint
POST /wp-json/auctionforge/v1/sync/cancel-all(X-API-Key auth) — runsSyncQueue::cancelAll()+ SIGTERM + watchdog. Logs every action throughSyncLogger. POST /sync/startextended with amodeparameter (upcomingdefault,pastfor archived). Bulk re-sync is now a queued job, not a synchronous block.- New job types
full_sync_upcomingandfull_sync_pastonSyncQueue, dispatched to a newBulkSyncWorkerthat wraps the existingAuctionList::init()+LotList::init($upcoming)pipeline. syncWorker.phpinstalls a SIGTERM handler that flips the in-flight job tofailedwith a "Killed by admin (SIGTERM, cleanup OK)" marker and closes the DB cleanly before exiting. Watchdog escalates to SIGKILL after 5 s grace.LotList::auctionProcessing()now heartbeats the active bulk-sync job between auctions, preventing the safety cron from auto-failing long bulk runs as stale (the 600 s threshold is unchanged).
Files Changed
- Modified:
auctionforge.php,inc/sync/SyncLogger.php,inc/sync/SyncQueue.php,inc/class-auto-updater.php,crontasks/syncWorker.php,inc/import/LotList.php - Created:
inc/sync/BulkSyncWorker.php
---
[3.6.1.6] — 2026-04-29
High-Value Lot Modes for
[bp_lot_list]Features
high_value_pastmode — Displays past auction lots ordered by their catalog estimate (estimatedPriceInt), highest first. Useful for "Top Lots" or "Highlights" sections.high_value_soldmode — Displays past sold lots ordered by their actual sold price (soldBid), highest first. Only includes genuinely sold lots (soldBid > 0) and reuses the same false-positive guard asrandom_pastto skip lots wheresoldBidwas carried over fromstartPricewithout real bidding activity.- Admin documentation updated — The Shortcodes reference page in WP Admin now lists both new modes in the
modeattribute description and includes example shortcode usage.
Architecture
- New constants
MODE_HIGH_VALUE_PASTandMODE_HIGH_VALUE_SOLDonLotsWidget. - New method
LotsWidget::getLotListHighValue($mode, $limit)builds the query, applies the past-auction tax filter, setsbp_orderbyto the relevant meta field withDESCorder, and (for the sold variant) filters out unsold-but-stale lots in PHP. - New filter hook
bp_lot_list_high_value_args_filterfor downstream customization of the WP_Query args.
Files Changed
- Modified:
inc/widgets/LotsWidget.php,inc/controllers/ShortcodesPage.php
---
[3.6.0.18] — 2026-04-25
Brevo SMS Notifications Integration
Features
- Transactional SMS via Brevo API — The plugin now sends text message alerts through the Brevo transactional SMS service, running alongside existing Firebase push notifications.
- Four Notification Types:
- New Auction Published — Broadcast SMS to all opted-in subscribers when an auction is published.
- Auction Starting Soon — Targeted SMS to users registered for an auction when it is about to start.
- Favorited Item Live Soon — Targeted SMS to users who favorited a lot when it is approaching in the auction.
- Outbid Notice — SMS sent when a user's leading bid is surpassed, with a 5-minute per-item cooldown to prevent spam.
- SMS Subscriber Database — New
af_sms_subscriberstable stores user phone numbers, country codes, and per-notification-type opt-in preferences (GDPR-ready explicit consent). - Admin Settings Tab — New "SMS Notifications" tab in Settings with:
- Brevo API Key input
- SMS Sender Name (11 char max)
- Master enable/disable toggle
- Per-notification-type on/off switches
- Test SMS widget with phone input and send button
- Live subscriber count display
- Profile SMS Preferences — Users can opt into SMS notifications directly from their profile page with phone number entry and granular notification type selection.
Architecture
- BrevoSMS Service (
inc/services/BrevoSMS.php) — cURL-based API wrapper with broadcast, targeted, and single-send methods, message builders with 160-char limit awareness, rate limiting, and comprehensive error logging. - SMSSubscriber Model (
inc/model/SMSSubscriber.php) — CRUD operations, email-to-phone resolution, opt-in filtering, and upsert logic. - Webhook Integration — SMS dispatch hooks added to
AuctionsAPI.phpmethods:leading_bid_surpassed(),item_live_soon(),auction_starts_soon(), andauctionPublishedPush().
AJAX Handlers
auctionforge_sms_save— Save SMS preferences from profile pageauctionforge_sms_load— Load SMS preferences for profile pageauctionforge_sms_test— Admin-only test SMS endpoint
Database
- New table:
af_sms_subscribers— Phone numbers, country codes, per-notification opt-ins, timestamps
Files Changed
- Modified:
auctionforge.php,inc/coreIncludes.php,inc/controllers/AuctionsAPI.php,inc/controllers/Settings.php,admin/view/settings.php,templates/parts/profile-templates.php - Created:
inc/services/BrevoSMS.php,inc/model/SMSSubscriber.php
---
[3.6.0.7] — 2026-04-14
Hotfix
Fixes
- Namespace resolution — Fixed fatal error in
wp_footercommission label hook caused by unqualifiedSettingsHelperandSettingsclass references. Now uses fully qualified namespaces.
Files Changed
- Modified:
auctionforge.php
---
[3.6.0.6] — 2026-04-14
Commission Label Override Fix
Fixes
- Theme template override compatibility — Moved the commission label JS override from the
single-lot.phptemplate intoauctionforge.phpviawp_footerhook (priority 99). Sites with theme-level template overrides (e.g.themes/*/auctionforge/single-lot.php) were not picking up the inline script. Thewp_footerapproach works universally on all single lot pages.
Files Changed
- Modified:
auctionforge.php,templates/single-lot.php
---
[3.6.0.5] — 2026-04-14
Commission Label Override
Features
- Commission Label Setting — New dropdown in Settings → Appearance allowing admins to choose between "Buyer's Premium" (default) and "Auction House Commission" as the label displayed on lot pages. This overrides the Bidspirit JS client's default label using a MutationObserver that catches asynchronously injected text.
Files Changed
- Modified:
inc/controllers/Settings.php,templates/single-lot.php
---
[3.6.0.4] — 2026-04-12
Auction Approval Modal Redesign
Changes
- Removed BidSpirit Terms of Use — The generic BidSpirit "Terms of Use" section that appeared at the top of the non-credit-card approval modal has been removed. The modal now shows only the auction house's own legal agreements managed within the plugin.
- Renamed Modal Title — Changed "Terms of conditions" to "Terms & Conditions".
- Larger Scroll Area — The Terms & Conditions scroll box is now 350px tall (up from 200px) for easier reading.
- Proportional Section Heights — Refund & Return Policy and Chargeback Waiver sections use a shorter 260px scroll box to visually distinguish them from the primary Terms & Conditions.
Files Changed
- Modified:
templates/js-chunks/approval-info.php,assets/js/app.js
---
[3.6.0.2] — 2026-04-10
Webhook Token Generator
Features
- Token Generator Widget — Added a 16-character random token generator directly below the "Webhook auth token" field on the Settings page. Includes a "Generate Token" button and a clipboard copy icon with visual feedback.
Files Changed
- Modified:
inc/controllers/Settings.php
---
[3.6.0.1] — 2026-04-10
Patch
Changes
- Version bump.
---
[3.6.0.0] — 2026-04-10
Legal Agreements for Auction Approval
Features
- Terms & Conditions — A mandatory, scrollable Terms & Conditions document is now displayed during the auction approval process. Bidders must scroll to the bottom and check an agreement box before their approval request is submitted. Always enabled.
- Refund & Return Policy — An optional, scrollable Refund & Return Policy can be enabled in Settings. When enabled, bidders must read and accept it during auction approval.
- Chargeback Waiver — An optional, scrollable Chargeback Waiver can be enabled in Settings. When enabled, bidders must read and accept it during auction approval.
- Admin Management — New "Legal Agreements" page under the Bidspirit admin menu with tabbed TinyMCE editors for each agreement type. Includes automatic version numbering (incremented on content change) and full version history.
- Consent Logging — Every agreement acceptance is logged to a dedicated database table (
af_user_agreement_log) with the agreement type, version, user email, IP address, user agent, auction ID, and timestamp. - User Tracking Integration — Agreement events (
terms_agreement,refund_agreement,chargeback_waiver) are also recorded in the existing IP tracking system alongside registration, login, and bid events. - Placeholder Content — Default sample content is seeded on plugin activation for all three agreement types.
Settings Added
- Enable Refund & Return Policy — Toggle to require bidders to accept the refund policy during auction approval.
- Enable Chargeback Waiver — Toggle to require bidders to accept the chargeback waiver during auction approval.
Database
- New table:
af_legal_agreements— Current active agreement content per type - New table:
af_legal_agreement_versions— Version history archive - New table:
af_user_agreement_log— User consent records
Files Changed
- Modified:
auctionforge.php,inc/controllers/Settings.php,inc/controllers/BidspiritViews.php,inc/ip-logger.php,templates/js-chunks/approval-info.php,assets/js/app.js - Created:
inc/legal/class-legal-agreements.php,admin/view/legal-agreements.php
---
[3.5.0.6] — 2026-04-08
Bid Event Tracking
Features
- Bid Tracking — All successful bids (regular, catalog, pre-sale buyout, post-sale purchase) now fire
afLogIP("bid", bidspiritUser)to capture the bidder's full identity in the user tracking table. - Whitelist Update — Added
bidto the allowedevent_typevalues in both the local plugin and the central WPDeploy API.
---
[3.5.0.5] — 2026-04-08
Self-Healing Database Schema
Features
- Auto-Migration — The plugin now auto-detects and adds any missing tracking table columns on version upgrade, ensuring sites with older schemas seamlessly migrate without manual SQL.
---
[3.5.0.4] — 2026-04-08
API Key Auto-Healing
Features
- Seamless Self-Registration — The WordPress plugin now autonomously regenerates and saves a fresh API Key whenever WPDeploy rejects a payload with an
api_key_collisionerror. This guarantees zero-downtime security handovers when developers clone instances to proxy/staging servers.
---
[3.5.0.3] — 2026-04-08
API Key Collision Defense
Features
- 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_collisionerrors, directly instructing developers to update cloned keys.
---
[3.5.0.2] — 2026-04-08
Modal Trigger Hotfix
Fixes
- Restructured internal UI rendering priority to gracefully deploy the inline Modal triggers inside custom IP log view without colliding with cached
z-indexstacks.
---
[3.5.0.1] — 2026-04-08
Hotfix
Fixes
- Timed Auction Badge Visibility — Fixed a strict type-matching bug in the main
auction_list.phpcore file that incorrectly hid the "Timed Auction" badge overlay from valid timed/online auctions on the main upcoming/archive views. The badge now displays properly across all manual and Bidspirit-synced objects when toggled on.
Files Changed
- Modified:
templates/main/auction_list.php
---
[3.2.9.1] — 2026-03-30
Timed Auction Display Enhancements
Features
- Timed Auction Countdown Text Toggle — Added a WP-Admin setting "Change text to 'Auction will close in'" that conditionally changes the countdown label for timed/online auctions on single lot pages.
- Shortcode Text Toggle Support — Extended the new countdown text logic to the
bp_upcoming_wideshortcodes so "Live bidding starts in:" successfully transitions to "Auction will close in:" for timed auctions.
Files Changed
- Modified:
inc/controllers/Settings.php,templates/single-lot.php,templates/shortcodes/upcoming-auction-wide.php,templates/shortcodes/upcoming-auction-wide-manual.php
---
[3.2.9.0] — 2026-03-29
Billing & Invoices Polish
Fixes
- Profile Invoice ID Tracking — Prevented internal auction codes (e.g.
002orai4) from breaking into the clean hyphenated titles inside theprofile-templates.phpview. - Dynamic Payment Statuses — Replaced Bidspirit's default/cached
NOT PAIDHTML payloads by wiring thedompdfgenerator to directly respect the current$b.statusstring from the API (resolving instances where a paid invoice still printed "NOT PAID" atop the document). - Payment Instructions Conditional — Automatically hide the "Payment Instructions" block from the PDF footer when an invoice is fully paid.
- Improved Nomenclature — Changed "Invoice No:" to "Bidder No:" on document output to prevent confusion with static invoice ledger IDs.
---
[3.2.6.0] — 2026-03-28
Multi-Day Auction Lot Filtering Fix
Fixes
- Day 2+ showing lots from Day 1 in multi-day auctions — The
itemIndexcolumn inbp_meta_dataisvarchar(55), but the day-range filter inBidspiritQuery::bp_query_where()was comparing it as a string. With string comparison, lot numbers like'11','101'–'145'incorrectly fell between'1001'and'1450', causing Day 1 lots to leak into Day 2 results. Fixed by usingCAST(bpMeta.itemIndex AS UNSIGNED)for numeric comparison andintval()on the PHP-side boundary values. Letter lots (e.g.14A,1025A) are handled correctly —CASTstrips the suffix, keeping them grouped with their base lot number.
Files Changed
- Modified:
inc/controllers/BidspiritQuery.php
---
[3.2.5.9] — 2026-03-27
Catalog Page Fix
Fixes
- Duplicate preview hours on catalog pages — The
displayHoursfield was rendered twice: once via thebp_after_description_auctionhook inBidspiritViews.phpand once inline in the auction template. Removed the hook-based rendering to eliminate the duplication.
Files Changed
- Modified:
inc/controllers/BidspiritViews.php,templates/main/auction.php
---
[3.2.5] — 2026-03-19
Sync Reliability & Stuck Lot Prevention
Fixes
- CATALOG_PUBLISHED webhook now triggers catalog sync — Previously only sent push notifications without syncing lots. When the earlier AUCTION_CATALOG_UPDATED fired before the catalog was ready on BidSpirit, lots were never imported. CATALOG_PUBLISHED now calls
auctionCatalogUpdated()to trigger a full catalog sync when the catalog is actually available. - 0-lot API results now fail instead of silently succeeding — When BidSpirit API returns 0 lots (catalog not yet ready), the sync job now fails with an explicit error message, allowing the next webhook to create a fresh retry job.
- Expanded CDN allowlist in pre_http_request filter — The HTTP filter during bulk post insertion now allows all
*.bidspirit.comsubdomains and BidSpirit image CDNs (fastly.net,cloudfront.net). Previously onlybidspirit.comandwww.bidspirit.comwere allowed, blocking image downloads during sync and causing worker hangs. - InsertLotsBS timeout guard — Stage 5 (InsertLotsBS processing loop) now has a 180-second timeout and logs progress every 2 batches. Prevents indefinite hangs that previously required manual force-kill.
- fixResult() no longer marks lots as done when postId=0 — When
lotProcessing()fails to create a WP post, the staging row now keepssyncFinished=0so the lot is retried on the next sync pass, instead of being permanently marked as complete with no actual post. - lotProcessing() logs error on missing auction term — Previously returned 0 silently when
Auction::findAuctionById()failed. Now logs an explicit error that feeds intofixResult()to keep the lot retryable. - Hourly orphan detection in safety cron — New step in
syncSafety.phpdetects lot posts that exist inbp_meta_databut are missing their auction taxonomy assignment (caused by workers killed mid-batch) and auto-repairs them withwp_set_object_terms().
Files Changed
- Modified:
inc/controllers/AuctionsAPI.php,inc/sync/CatalogSyncWorker.php,inc/abs/InsertLotsAbstract.php,inc/import/InsertLotsBS.php,crontasks/syncSafety.php
---
[3.2.4] — 2026-03-18
Sync Worker Hang Fix
Fixes
- Sync workers hanging at InsertLotsBS stage — Third-party plugins (Smush Pro, SmartCrawl SEO, WPMU DEV Updates) hook into
wp_insert_post()and make blocking outbound HTTPS calls for every lot processed. With 489+ lots per auction, this caused workers to hang indefinitely on socket reads to WPMU DEV servers (32.193.94.25,32.193.93.106). AddedWP_IMPORTINGconstant at the REST worker entry point and apre_http_requestfilter inCatalogSyncWorkerthat blocks all non-essential external HTTP during the batch post-insertion phase. Loopback (127.0.0.1,localhost) and BidSpirit API calls remain allowed. - Stuck staging rows after force-kill — When workers were force-killed mid-sync, staging rows in
import_historywere left withsyncstart=1and never unblocked. Subsequent sync runs could not see these rows (filtered out byLot::getRawLots()), causing the InsertLotsBS loop to exit immediately with 0 posts processed. Combined with job deduplication (SyncQueue::enqueue()skips if aprocessingjob exists), this created a deadlock where no new sync could proceed.
Files Changed
- Modified:
auctionforge.php,inc/sync/CatalogSyncWorker.php
---
[3.2.2] — 2026-03-17
Full Sync Auction Discovery Fix
Fixes
- Full Sync finds no auctions on fresh sites — The v3
full_syncaction only queried the WordPress database for existing auction terms, but on a freshly deployed site the database has zero auctions. AddedAuctionList::init()discovery step before querying the DB, so Full Sync now fetches all auctions from the BidSpirit API and creates taxonomy terms first, then enqueues catalog sync jobs for each.
Files Changed
- Modified:
auctionforge.php
---
[3.2.0] — 2026-03-14
Webhook Pipeline Fixes, Archive Sync & Admin UI Overhaul
New Features
- Archive Sync — New "Archive Sync" button on Sync Status admin page. Enqueues catalog sync jobs for all ARCHIVED/ENDED auctions. Past auctions now appear in the auction dropdown with an optgroup separator and state label.
- Sync Tasks v3 — Replaced old v2 task cards (importData, importBidSpirit, lotBidSpiritOld) with v3 queue-based tasks. "Sync Active Auctions" and "Sync Archived Auctions" now enqueue jobs via the queue system. Maintenance tasks (Clean Draft/Trash Lots, Clean Orphaned Meta) remain as direct-execution tasks.
- How It Works guide rewritten — Complete rewrite of the admin guide for v3 architecture. Documents webhook-first flow, all 5 job types, queue system mechanics, cron setup (external + WP-Cron), configuration constants, and troubleshooting.
Fixes
- Dual-write removed — Removed legacy handlers from
auctionCatalogUpdated(),auctionDayEnded(), anditemsUpdated()webhook methods. The old handlers were racing with the v3 worker, creating orphaned staging rows inimport_historythat were never processed. All three methods now exclusively use the v3 enqueue → spawn path. - ITEMS_UPDATED webhook — Fixed
itemsUpdated()failing to enqueue jobs. TheITEMS_UPDATEDpayload hasauctionIdnested initemsByLanguage.{lang}[0].item.auctionId, not at the top level. Added extraction logic to resolve it. - ItemUpdateWorker incomplete —
ItemUpdateWorker::process()was only callingLot::bulkSave()(staging table) without runningInsertLotsBSto process staged data into WP posts andbp_meta_data. Added the InsertLotsBS processing step with autocommit restore. Item updates now flow: stage → InsertLotsBS → WP post + meta → cache clear. - Worker spawn reliability — Changed
SyncQueue::spawnWorker()from non-blocking HTTPS to blocking HTTP loopback (http://127.0.0.1with explicitHostheader, 2s timeout). Fixes nginx 403/404 errors when HTTPS loopback hits the default vhost instead of the site's vhost. - API token constant — Plugin expects
AUCTIONFORGE_API_TOKENinwp-config.php(renamed fromUCO_API_TOKENduring the plugin rename). Documented in readme.
Database
- DB version: 22 → 23
Files Changed
- Modified:
inc/controllers/AuctionsAPI.php,inc/sync/ItemUpdateWorker.php,inc/sync/SyncQueue.php,auctionforge.php,admin/view/sync-status.php,readme.txt
---
[3.0.0] — 2025-03-14
New Feature: Webhook-First Sync Architecture (Sync v3)
Overview: Complete redesign of the BidSpirit data synchronisation pipeline. Replaces the old two-phase polling system (importBidSpirit every hour + importData every minute) with a webhook-driven job queue that processes data in near real-time.
Architecture
- 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: webhook → queue → background worker → WordPress posts. - Dual-write mode — During transition, webhooks enqueue jobs AND still run the legacy handlers. Once verified, legacy handlers can be removed cleanly.
- Job deduplication — Prevents duplicate work by checking for existing pending/processing jobs with the same auction_id + job_type.
New Components
- Job Queue System (
inc/sync/SyncQueue.php) — Priority-based FIFO queue with atomic job claiming, status tracking (pending/processing/completed/failed/skipped), worker PID tracking, and automatic stuck job recovery. - Sync Logger (
inc/sync/SyncLogger.php) — Real-time log table for admin console polling with level filtering (info/success/warning/error) and incremental cursor-based retrieval. - Catalog Sync Worker (
inc/sync/CatalogSyncWorker.php) — Processes catalog_sync, full_sync, and day_ended jobs by reusing existingLotList::singleRun()logic. - Item Update Worker (
inc/sync/ItemUpdateWorker.php) — Processes individual item_update jobs with the same logic as the webhookitemsUpdatedhandler. - Background Worker (
crontasks/syncWorker.php) — Async CLI process spawned by webhooks viaexec()or by the safety cron. Claims and processes queued jobs with a configurable timeout (default 240s). - Safety Net (
crontasks/syncSafety.php) — Hourly cron that resets stuck jobs (>10min), spawns workers for pending jobs, runs a 24-hour health check (auto-enqueues full sync if no webhooks received), and purges old data.
Admin UI
- Queue Status Dashboard — New card on Sync Status page showing pending/processing/completed/failed/skipped counts, recent jobs table with real-time refresh, worker status badge, and action buttons:
- Full Sync — Enqueues catalog sync for all active auctions
- Sync Selected — Enqueue a single auction from dropdown
- Spawn Worker — Manually trigger a background worker process
- Live Console — Dark-themed terminal console on the Sync Status page. Polls
af_sync_logevery 1.5s showing timestamped, color-coded log entries from webhooks, workers, queue operations, and the safety cron. Supports pause, clear, and auto-scroll.
Cron Changes
- Removed
importData(ran every minute — ~1,440 PHP executions/day) - Removed
importBidSpirit(ran hourly — ~24 PHP executions/day) - Added
syncSafety(runs hourly at :10 — 24 PHP executions/day) - Net effect: ~62 PHP executions/hour → 1 PHP execution/hour
- WP-Cron safety hook (
auctionforge_sync_safety) — Always-active hourly event, independent of external cron - setup.sh v3 — Updated task definitions, new
migratecommand for interactive v2→v3 transition
Database
- New table:
af_sync_queue— Job queue with status, priority, source, attempts, worker PID, timing columns - New table:
af_sync_log— Real-time log entries with context, level, auction_id, job_id - DB version: 20 → 22
Constants Added
| Constant | Default | Description |
|---|---|---|
|
AUCTIONFORGE_SYNC_WORKER_TIMEOUT| 240 | Worker process timeout in seconds ||
AUCTIONFORGE_SYNC_STALE_JOB| 600 | Seconds before a processing job is considered stuck ||
AUCTIONFORGE_SYNC_HEALTH_CHECK| 86400 | Seconds without webhook before triggering full sync ||
AUCTIONFORGE_SYNC_LOG_RETENTION| 7 | Days to keep log entries ||
AUCTIONFORGE_SYNC_QUEUE_RETENTION| 30 | Days to keep completed queue jobs ||
AUCTIONFORGE_CURL_TIMEOUT| 30 | BidSpirit API cURL timeout in seconds ||
AUCTIONFORGE_PHP_BINARY| /www/server/php/83/bin/php | PHP CLI binary path for spawning workers |AJAX Handlers Added
auctionforge_sync_log_poll— Incremental log polling for live consoleauctionforge_sync_queue_status— Queue counts + recent jobs for dashboardauctionforge_sync_enqueue— Admin-triggered sync actions (full_sync, sync_auction, spawn_worker)
Fixes
- cURL timeout — BidSpiritRequest now enforces a 30-second timeout (was unlimited/0), preventing hung connections from blocking the sync pipeline.
Files Changed
- Modified:
auctionforge.php,inc/coreIncludes.php,inc/controllers/AuctionsAPI.php,inc/BidSpiritRequest.php,admin/view/sync-status.php,crontasks/setup.sh - Created:
inc/sync/SyncQueue.php,inc/sync/SyncLogger.php,inc/sync/CatalogSyncWorker.php,inc/sync/ItemUpdateWorker.php,crontasks/syncWorker.php,crontasks/syncSafety.php
---
[2.7.3.0]
Fixes
- Various stability improvements and bug fixes.
[2.7.1.2]
Fixes
- Added missing
vatAndCommission()function inloadBid()— the sales tax display on single lot pages was never being rendered because the code to callloadTemplateforvat-and-commission-templatewas missing fromapp.js.
[2.7.1.1]
Fixes
- 2 decimal places now only appear in the bid modal (Your max bid, Total Price) via
showDecimalsflag. 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.
[2.7.0.9]
Fixes
- Fixed fatal error during plugin install/upgrade:
class-stats-database.phprequire failure.
[2.7.0.0]
New Features: Advanced Lot Analytics
- Conversion Tracking, Peak Viewing Times, Pre-Sale vs Live Comparison, Category Performance, Share Analytics, Search → View Funnel, Click-Through Tracking, CSV Export, Hot Lot Badge.
- New DB table:
af_lot_shares. New columns onaf_lot_analytics. DB version bumped to 20.
[2.6.0.0]
New Feature: Lot Analytics
- Comprehensive lot view and favorite tracking system with admin dashboard.
[2.5.0.0]
New Features
- Site Statistics System — Full website analytics built into the plugin admin.
- Recently Viewed Items — Profile page tab showing last 20 viewed lots per user.
- InsertLotsBS loop break condition — The stage 5 insert loop in
-
v3.6.3.1 Stable May 01, 2026Download v3.6.3.1📦 9.19 MB⚙️ WP 5.2+🔧 PHP 7.2+✓ Tested 6.4
[3.6.3.1] — 2026-05-01
Fix: New lots never processed + Live console improvements
Why
When BidSpirit adds new lots to an auction (e.g. items 683-692), the sync pipeline correctly staged all 709 lots into
import_historybut the InsertLotsBS processing loop exited after the first batch of 500 unchanged lots, never reaching the genuinely new lots at the tail of the queue. This caused new lots to remain permanently stuck in staging — synced but never created as WordPress posts.Separately, the admin Live Console was replaying the entire log history from the beginning on every page load, and showed long silent gaps during API calls with no indication of what the worker was doing.
Fixes
- InsertLotsBS loop break condition — The stage 5 insert loop in
CatalogSyncWorker::process()andprocessDayEnded()previously broke whenupdated lots === 0, even if the batch had cleared hundreds of unchanged ("unupdated") lots from the queue. New lots with higher IDs were never reached. Now breaks only when bothupdated lotsandunupdated lotsare 0, meaning the staging queue is truly empty. - Live Console starts from current position —
consoleSinceIdwas hardcoded to0, causing the console to page through the entireaf_sync_logtable (50 rows at a time) before reaching real-time entries. Now initializes toSyncLogger::getLatestId()so only entries created after page load appear. queueIsActivedeclaration order — Variable was declared after functions that referenced it, causing the console to always start at the slow 3s polling rate even when a worker was active. Moved declaration before first use.- Progress logging during API calls —
LotList::auctionProcessing()made 2-3 BidSpirit API calls with zeroSyncLoggerentries, creating long silent gaps in the console. Added log entries for API fetch start, response received (with duration), data staged, and API errors. - Per-auction progress in bulk runs —
LotList::run()now logsProcessing auction X/Y: {id}for each auction in the bulk loop, and logs skipped auctions. processDayEndedinsert loop logging — Added batch progress logging and timeout guard matching theprocess()method pattern. Previously this loop was completely silent.
Files Changed
- Modified:
inc/sync/CatalogSyncWorker.php,inc/import/LotList.php,admin/view/sync-status.php
---
- InsertLotsBS loop break condition — The stage 5 insert loop in
-
v3.6.3.0 Stable May 01, 2026Download v3.6.3.0📦 8.97 MB⚙️ WP 5.2+🔧 PHP 7.2+✓ Tested 6.4
[3.6.3.0] — 2026-05-01
Public Auctions API — Token Authentication
Why
The
/wp-json/auctionforge/v1/public/auctionsendpoint added in v3.6.2.9 was publicly accessible. Since auction data should only be served to authorized aggregator sites, the endpoint now requires a valid auth token.Changes
- Token verification — The
PublicAuctionsREST endpoint now validates anX-AF-Tokenheader (or?token=query parameter) against the site's existing Webhook auth token from AuctionForge settings. - Returns
401 Unauthorizedfor missing/invalid tokens and403 Forbiddenif no auth token is configured on the site. - Uses
hash_equals()for timing-safe comparison.
Files Changed
- Modified:
auctionforge.php,inc/api/PublicAuctions.php
---
- Token verification — The
-
v3.6.2.9 Stable May 01, 2026Download v3.6.2.9📦 8.97 MB⚙️ WP 5.2+🔧 PHP 7.2+✓ Tested 6.4
AuctionForge Changelog
All notable changes to the AuctionForge plugin are documented in this file.
---
[3.6.2.8] — 2026-04-30
Suppress alerts for transient retry conditions
Why
The "BidSpirit API returned 0 lots — catalog may not be ready yet" message is logged when the BidSpirit webhook fires before the auction catalog is fully published. The safety cron retries the job automatically and it usually succeeds on the next attempt — there's no operator action required, so a Telegram alert is just noise.
Fix
- New private helper
SyncLogger::isSuppressedFromAlerts($message, $context)matches the message against a substring allowlist of known-transient errors. When matched, the row is still inserted intoaf_sync_log(so the in-app sync console still shows the retry chain) but theauctionforge_sync_error_loggedfan-out action does NOT fire — wpdeploy and Telegram stay quiet. - Default suppression substrings:
"BidSpirit API returned 0 lots","catalog may not be ready yet". - Extendable via the new
auctionforge_sync_alert_suppress_patternsfilter — themes/MU plugins can add their own substrings.
Files Changed
- Modified:
auctionforge.php,inc/sync/SyncLogger.php
---
[3.6.2.7] — 2026-04-30
Typo fix
- Settings → Connections tab: the placeholder/help text under the Server field showed
https://my-accaunt.bidspirit.com/(extra "a"). Now readshttps://my-account.bidspirit.com/.
Files Changed
- Modified:
auctionforge.php,inc/controllers/Settings.php
---
[3.6.2.6] — 2026-04-30
Fix stale
plugin_versionin reportsWhy
Sites were reporting their old version to wpdeploy long after they'd been upgraded — e.g. Lonsdale Auctioneers ran v3.6.1.1 but kept telling wpdeploy it was on v2.9.6. Root cause: the constant
AUCTIONFORGE_VERSIONis read from the plugin file'sVersion:header *once at plugin load*, then frozen into$this->current_versionon the auto-updater instance. After a plugin upgrade replaces the file on disk, existing PHP-FPM workers keep using the cached constant value until they're recycled, so every report from those workers carries the old version.Fix
- New helper
AuctionForge_Auto_Updater::get_live_version()reads the version directly from the plugin file's header on each call (viaget_file_data()— uncached). report_health,push_sync_error_immediate, andretry_sync_errorsnow sendget_live_version()instead of the cached constant.- The pre-existing iteration through active plugins inside
report_healthalready usedget_plugin_data()per plugin, so secondary plugin entries were already accurate; only the top-levelplugin_versionfield was stale.
Files Changed
- Modified:
auctionforge.php,inc/class-auto-updater.php
---
[3.6.2.5] — 2026-04-30
Real diagnostics for plugin self-updates
Why
The wpdeploy
update_queuetable had a 46% historical failure rate, but every single failure row stored the literal string"Installation failed"— collapsing every failure mode into one opaque error with no diagnostic value. Root cause: theinstall_update()method in both clients (AF auto-updater and wpd-client) treatedPlugin_Upgrader::upgrade()as a boolean, throwing awayWP_Errorobjects and skin-emitted error messages.Fixes (
inc/class-auto-updater.phpinstall_update())- Refreshes the
update_pluginstransient before invoking the upgrader. The upgrader reads from this transient to know what version to download; if WP hasn't checked recently, the upgrader silently returns false (looking like a failure even though there's a real update queued at wpdeploy). - Distinguishes
WP_Error,false/null, and success.WP_Errorwas previously treated as truthy → reported as "completed" even on failure. Now extracts the error code and message. - Reads
Automatic_Upgrader_Skin::get_errors()to surface the real upgrader-emitted error messages. - Reads
$upgrader->resultwhich holds the finalWP_Errorfor some failure paths. - Captures PHP errors/warnings emitted during the upgrade (file-move issues, etc.) via a temporary
set_error_handler. - Detects "no update in transient" as a distinct failure cause and labels it explicitly so we know it's a transient-cache problem, not an actual install failure.
- Truncates the combined diagnostic to 1000 chars before sending.
The same fix is applied to
wpd-client.php(the WPD client plugin shipped fromclient-plugin/wpd-client.phpon the wpdeploy server).Files Changed
- Modified:
auctionforge.php,inc/class-auto-updater.php
---
[3.6.2.4] — 2026-04-30
Bulk-sync worker dispatch fix
Fixes
- The HTTP-loopback worker (
auctionforge_rest_sync_workerinauctionforge.php) had its own switch statement for job-type dispatch, distinct from the one incrontasks/syncWorker.php. The newfull_sync_upcomingandfull_sync_pastjob types were only added to the CLI worker, so the loopback path produced "Unknown job type" errors. Both switches now route those types toBulkSyncWorker::process. inc/coreIncludes.phpnowrequire_oncesBulkSyncWorker.phpso the class is available wherever sync code runs.
Files Changed
- Modified:
auctionforge.php,inc/coreIncludes.php
---
[3.6.2.3] — 2026-04-30
Fixes for end-to-end Telegram round-trip
Fixes
verify_api_keyreads the option fresh on every call (hash_equalsagainstget_option('auctionforge_update_api_key')) instead of relying on the cached$this->api_keyfrom constructor time. Different FPM workers can hold different cached values when the option drifts (e.g. via auto-heal collisions), which previously produced intermittent 401s on REST endpoints.- New REST endpoint
POST /wp-json/auctionforge/v1/sync/version— wraps the existingtrigger-installflow with a JSON response (always HTTP 200 withsuccessflag). The original endpoint returnedWP_Error('no_update', …, status: 404)when the plugin was already on the latest version, which nginx'serror_page 404directive then clobbered with a static HTML 404 page on hosts using aaPanel/BTWAF. Keeping the URL under/sync/*matches the pattern that's already proven to pass through host WAFs.
Files Changed
- Modified:
auctionforge.php,inc/class-auto-updater.php
---
[3.6.2.2] — 2026-04-29
Catalog-sync kind disambiguation
Fix
catalog_syncjobs target a single auction that may be either active or archived. Until now their alerts were always classified askind=upcoming. The classifier now resolves the auction'sauction_stateterm meta and routes:ARCHIVED/ENDED/POST_AUCTION→kind=past→ Kill + Full Past buttons- anything else (or unresolvable) →
kind=upcoming→ Kill + Full Upcoming buttons
Files Changed
- Modified:
auctionforge.php,inc/class-auto-updater.php
---
[3.6.2.1] — 2026-04-29
Telegram Sync Monitoring follow-ups
Features
- Context-aware alert buttons. Each Telegram alert now shows the action set most relevant to the failing sync: upcoming-sync errors get Kill + Full Upcoming, past-sync errors get Kill + Full Past, everything else gets Kill only. Button choice is driven by a new
kindfield classified at log-write time from the queue'sjob_type. - Plugin version in alerts + Update button. Each push now includes the live
plugin_version. wpdeploy compares it to the latestis_stable=1row in itsversionstable and only renders an Update plugin button when the site is behind. Tapping Update calls the existingPOST /wp-json/auctionforge/v1/trigger-installendpoint to force the upgrade.
Architecture
- New private helper
AuctionForge_Auto_Updater::classify_error_kind($jobId)looks up the job'sjob_typeand maps it to'upcoming'/'past'/'other'. Used by both the immediate push and the 1-min retry cron. - Outbound payloads now include
plugin_versionat the top level; wpdeploy refreshessites.plugin_versionon every/sync-errorsPOST.
Files Changed
- Modified:
auctionforge.php,inc/class-auto-updater.php
---
[3.6.2.0] — 2026-04-29
Telegram Sync Monitoring & Remote Control
Features
- Instant Telegram alerts on sync errors. Any
level='error'row written toaf_sync_logis pushed (fire-and-forget, non-blocking) to wpdeploy, which fans it out to a configured Telegram group with inline-keyboard action buttons (Kill / Full Upcoming / Full Past / Acknowledge). - Remote command surface. Any group admin can tap a button to:
- Kill sync — flips DB flags via
SyncQueue::cancelAll(), then SIGTERMs every active worker; a 5-second watchdog escalates to SIGKILL for any survivor. - Full sync upcoming — full re-import of every active auction and its lots (queued, observable, killable). Replaces the
re-sync?do=importBidSpiritUpcomingflow with a queued equivalent. - Full sync past — same, for archived auctions.
- Safety-net retry cron (
auctionforge_retry_sync_errors, every minute) re-pushes recent error rows. wpdeploy dedupes viaUNIQUE(site_id, af_log_id)so duplicates are silent.
Architecture
SyncLogger::log()now firesdo_action('auctionforge_sync_error_logged', …)onlevel='error'so any handler can react. The auto-updater listener does a 2 s non-blocking POST to/api.php/sync-errors.- New REST endpoint
POST /wp-json/auctionforge/v1/sync/cancel-all(X-API-Key auth) — runsSyncQueue::cancelAll()+ SIGTERM + watchdog. Logs every action throughSyncLogger. POST /sync/startextended with amodeparameter (upcomingdefault,pastfor archived). Bulk re-sync is now a queued job, not a synchronous block.- New job types
full_sync_upcomingandfull_sync_pastonSyncQueue, dispatched to a newBulkSyncWorkerthat wraps the existingAuctionList::init()+LotList::init($upcoming)pipeline. syncWorker.phpinstalls a SIGTERM handler that flips the in-flight job tofailedwith a "Killed by admin (SIGTERM, cleanup OK)" marker and closes the DB cleanly before exiting. Watchdog escalates to SIGKILL after 5 s grace.LotList::auctionProcessing()now heartbeats the active bulk-sync job between auctions, preventing the safety cron from auto-failing long bulk runs as stale (the 600 s threshold is unchanged).
Files Changed
- Modified:
auctionforge.php,inc/sync/SyncLogger.php,inc/sync/SyncQueue.php,inc/class-auto-updater.php,crontasks/syncWorker.php,inc/import/LotList.php - Created:
inc/sync/BulkSyncWorker.php
---
[3.6.1.6] — 2026-04-29
High-Value Lot Modes for
[bp_lot_list]Features
high_value_pastmode — Displays past auction lots ordered by their catalog estimate (estimatedPriceInt), highest first. Useful for "Top Lots" or "Highlights" sections.high_value_soldmode — Displays past sold lots ordered by their actual sold price (soldBid), highest first. Only includes genuinely sold lots (soldBid > 0) and reuses the same false-positive guard asrandom_pastto skip lots wheresoldBidwas carried over fromstartPricewithout real bidding activity.- Admin documentation updated — The Shortcodes reference page in WP Admin now lists both new modes in the
modeattribute description and includes example shortcode usage.
Architecture
- New constants
MODE_HIGH_VALUE_PASTandMODE_HIGH_VALUE_SOLDonLotsWidget. - New method
LotsWidget::getLotListHighValue($mode, $limit)builds the query, applies the past-auction tax filter, setsbp_orderbyto the relevant meta field withDESCorder, and (for the sold variant) filters out unsold-but-stale lots in PHP. - New filter hook
bp_lot_list_high_value_args_filterfor downstream customization of the WP_Query args.
Files Changed
- Modified:
inc/widgets/LotsWidget.php,inc/controllers/ShortcodesPage.php
---
[3.6.0.18] — 2026-04-25
Brevo SMS Notifications Integration
Features
- Transactional SMS via Brevo API — The plugin now sends text message alerts through the Brevo transactional SMS service, running alongside existing Firebase push notifications.
- Four Notification Types:
- New Auction Published — Broadcast SMS to all opted-in subscribers when an auction is published.
- Auction Starting Soon — Targeted SMS to users registered for an auction when it is about to start.
- Favorited Item Live Soon — Targeted SMS to users who favorited a lot when it is approaching in the auction.
- Outbid Notice — SMS sent when a user's leading bid is surpassed, with a 5-minute per-item cooldown to prevent spam.
- SMS Subscriber Database — New
af_sms_subscriberstable stores user phone numbers, country codes, and per-notification-type opt-in preferences (GDPR-ready explicit consent). - Admin Settings Tab — New "SMS Notifications" tab in Settings with:
- Brevo API Key input
- SMS Sender Name (11 char max)
- Master enable/disable toggle
- Per-notification-type on/off switches
- Test SMS widget with phone input and send button
- Live subscriber count display
- Profile SMS Preferences — Users can opt into SMS notifications directly from their profile page with phone number entry and granular notification type selection.
Architecture
- BrevoSMS Service (
inc/services/BrevoSMS.php) — cURL-based API wrapper with broadcast, targeted, and single-send methods, message builders with 160-char limit awareness, rate limiting, and comprehensive error logging. - SMSSubscriber Model (
inc/model/SMSSubscriber.php) — CRUD operations, email-to-phone resolution, opt-in filtering, and upsert logic. - Webhook Integration — SMS dispatch hooks added to
AuctionsAPI.phpmethods:leading_bid_surpassed(),item_live_soon(),auction_starts_soon(), andauctionPublishedPush().
AJAX Handlers
auctionforge_sms_save— Save SMS preferences from profile pageauctionforge_sms_load— Load SMS preferences for profile pageauctionforge_sms_test— Admin-only test SMS endpoint
Database
- New table:
af_sms_subscribers— Phone numbers, country codes, per-notification opt-ins, timestamps
Files Changed
- Modified:
auctionforge.php,inc/coreIncludes.php,inc/controllers/AuctionsAPI.php,inc/controllers/Settings.php,admin/view/settings.php,templates/parts/profile-templates.php - Created:
inc/services/BrevoSMS.php,inc/model/SMSSubscriber.php
---
[3.6.0.7] — 2026-04-14
Hotfix
Fixes
- Namespace resolution — Fixed fatal error in
wp_footercommission label hook caused by unqualifiedSettingsHelperandSettingsclass references. Now uses fully qualified namespaces.
Files Changed
- Modified:
auctionforge.php
---
[3.6.0.6] — 2026-04-14
Commission Label Override Fix
Fixes
- Theme template override compatibility — Moved the commission label JS override from the
single-lot.phptemplate intoauctionforge.phpviawp_footerhook (priority 99). Sites with theme-level template overrides (e.g.themes/*/auctionforge/single-lot.php) were not picking up the inline script. Thewp_footerapproach works universally on all single lot pages.
Files Changed
- Modified:
auctionforge.php,templates/single-lot.php
---
[3.6.0.5] — 2026-04-14
Commission Label Override
Features
- Commission Label Setting — New dropdown in Settings → Appearance allowing admins to choose between "Buyer's Premium" (default) and "Auction House Commission" as the label displayed on lot pages. This overrides the Bidspirit JS client's default label using a MutationObserver that catches asynchronously injected text.
Files Changed
- Modified:
inc/controllers/Settings.php,templates/single-lot.php
---
[3.6.0.4] — 2026-04-12
Auction Approval Modal Redesign
Changes
- Removed BidSpirit Terms of Use — The generic BidSpirit "Terms of Use" section that appeared at the top of the non-credit-card approval modal has been removed. The modal now shows only the auction house's own legal agreements managed within the plugin.
- Renamed Modal Title — Changed "Terms of conditions" to "Terms & Conditions".
- Larger Scroll Area — The Terms & Conditions scroll box is now 350px tall (up from 200px) for easier reading.
- Proportional Section Heights — Refund & Return Policy and Chargeback Waiver sections use a shorter 260px scroll box to visually distinguish them from the primary Terms & Conditions.
Files Changed
- Modified:
templates/js-chunks/approval-info.php,assets/js/app.js
---
[3.6.0.2] — 2026-04-10
Webhook Token Generator
Features
- Token Generator Widget — Added a 16-character random token generator directly below the "Webhook auth token" field on the Settings page. Includes a "Generate Token" button and a clipboard copy icon with visual feedback.
Files Changed
- Modified:
inc/controllers/Settings.php
---
[3.6.0.1] — 2026-04-10
Patch
Changes
- Version bump.
---
[3.6.0.0] — 2026-04-10
Legal Agreements for Auction Approval
Features
- Terms & Conditions — A mandatory, scrollable Terms & Conditions document is now displayed during the auction approval process. Bidders must scroll to the bottom and check an agreement box before their approval request is submitted. Always enabled.
- Refund & Return Policy — An optional, scrollable Refund & Return Policy can be enabled in Settings. When enabled, bidders must read and accept it during auction approval.
- Chargeback Waiver — An optional, scrollable Chargeback Waiver can be enabled in Settings. When enabled, bidders must read and accept it during auction approval.
- Admin Management — New "Legal Agreements" page under the Bidspirit admin menu with tabbed TinyMCE editors for each agreement type. Includes automatic version numbering (incremented on content change) and full version history.
- Consent Logging — Every agreement acceptance is logged to a dedicated database table (
af_user_agreement_log) with the agreement type, version, user email, IP address, user agent, auction ID, and timestamp. - User Tracking Integration — Agreement events (
terms_agreement,refund_agreement,chargeback_waiver) are also recorded in the existing IP tracking system alongside registration, login, and bid events. - Placeholder Content — Default sample content is seeded on plugin activation for all three agreement types.
Settings Added
- Enable Refund & Return Policy — Toggle to require bidders to accept the refund policy during auction approval.
- Enable Chargeback Waiver — Toggle to require bidders to accept the chargeback waiver during auction approval.
Database
- New table:
af_legal_agreements— Current active agreement content per type - New table:
af_legal_agreement_versions— Version history archive - New table:
af_user_agreement_log— User consent records
Files Changed
- Modified:
auctionforge.php,inc/controllers/Settings.php,inc/controllers/BidspiritViews.php,inc/ip-logger.php,templates/js-chunks/approval-info.php,assets/js/app.js - Created:
inc/legal/class-legal-agreements.php,admin/view/legal-agreements.php
---
[3.5.0.6] — 2026-04-08
Bid Event Tracking
Features
- Bid Tracking — All successful bids (regular, catalog, pre-sale buyout, post-sale purchase) now fire
afLogIP("bid", bidspiritUser)to capture the bidder's full identity in the user tracking table. - Whitelist Update — Added
bidto the allowedevent_typevalues in both the local plugin and the central WPDeploy API.
---
[3.5.0.5] — 2026-04-08
Self-Healing Database Schema
Features
- Auto-Migration — The plugin now auto-detects and adds any missing tracking table columns on version upgrade, ensuring sites with older schemas seamlessly migrate without manual SQL.
---
[3.5.0.4] — 2026-04-08
API Key Auto-Healing
Features
- Seamless Self-Registration — The WordPress plugin now autonomously regenerates and saves a fresh API Key whenever WPDeploy rejects a payload with an
api_key_collisionerror. This guarantees zero-downtime security handovers when developers clone instances to proxy/staging servers.
---
[3.5.0.3] — 2026-04-08
API Key Collision Defense
Features
- 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_collisionerrors, directly instructing developers to update cloned keys.
---
[3.5.0.2] — 2026-04-08
Modal Trigger Hotfix
Fixes
- Restructured internal UI rendering priority to gracefully deploy the inline Modal triggers inside custom IP log view without colliding with cached
z-indexstacks.
---
[3.5.0.1] — 2026-04-08
Hotfix
Fixes
- Timed Auction Badge Visibility — Fixed a strict type-matching bug in the main
auction_list.phpcore file that incorrectly hid the "Timed Auction" badge overlay from valid timed/online auctions on the main upcoming/archive views. The badge now displays properly across all manual and Bidspirit-synced objects when toggled on.
Files Changed
- Modified:
templates/main/auction_list.php
---
[3.2.9.1] — 2026-03-30
Timed Auction Display Enhancements
Features
- Timed Auction Countdown Text Toggle — Added a WP-Admin setting "Change text to 'Auction will close in'" that conditionally changes the countdown label for timed/online auctions on single lot pages.
- Shortcode Text Toggle Support — Extended the new countdown text logic to the
bp_upcoming_wideshortcodes so "Live bidding starts in:" successfully transitions to "Auction will close in:" for timed auctions.
Files Changed
- Modified:
inc/controllers/Settings.php,templates/single-lot.php,templates/shortcodes/upcoming-auction-wide.php,templates/shortcodes/upcoming-auction-wide-manual.php
---
[3.2.9.0] — 2026-03-29
Billing & Invoices Polish
Fixes
- Profile Invoice ID Tracking — Prevented internal auction codes (e.g.
002orai4) from breaking into the clean hyphenated titles inside theprofile-templates.phpview. - Dynamic Payment Statuses — Replaced Bidspirit's default/cached
NOT PAIDHTML payloads by wiring thedompdfgenerator to directly respect the current$b.statusstring from the API (resolving instances where a paid invoice still printed "NOT PAID" atop the document). - Payment Instructions Conditional — Automatically hide the "Payment Instructions" block from the PDF footer when an invoice is fully paid.
- Improved Nomenclature — Changed "Invoice No:" to "Bidder No:" on document output to prevent confusion with static invoice ledger IDs.
---
[3.2.6.0] — 2026-03-28
Multi-Day Auction Lot Filtering Fix
Fixes
- Day 2+ showing lots from Day 1 in multi-day auctions — The
itemIndexcolumn inbp_meta_dataisvarchar(55), but the day-range filter inBidspiritQuery::bp_query_where()was comparing it as a string. With string comparison, lot numbers like'11','101'–'145'incorrectly fell between'1001'and'1450', causing Day 1 lots to leak into Day 2 results. Fixed by usingCAST(bpMeta.itemIndex AS UNSIGNED)for numeric comparison andintval()on the PHP-side boundary values. Letter lots (e.g.14A,1025A) are handled correctly —CASTstrips the suffix, keeping them grouped with their base lot number.
Files Changed
- Modified:
inc/controllers/BidspiritQuery.php
---
[3.2.5.9] — 2026-03-27
Catalog Page Fix
Fixes
- Duplicate preview hours on catalog pages — The
displayHoursfield was rendered twice: once via thebp_after_description_auctionhook inBidspiritViews.phpand once inline in the auction template. Removed the hook-based rendering to eliminate the duplication.
Files Changed
- Modified:
inc/controllers/BidspiritViews.php,templates/main/auction.php
---
[3.2.5] — 2026-03-19
Sync Reliability & Stuck Lot Prevention
Fixes
- CATALOG_PUBLISHED webhook now triggers catalog sync — Previously only sent push notifications without syncing lots. When the earlier AUCTION_CATALOG_UPDATED fired before the catalog was ready on BidSpirit, lots were never imported. CATALOG_PUBLISHED now calls
auctionCatalogUpdated()to trigger a full catalog sync when the catalog is actually available. - 0-lot API results now fail instead of silently succeeding — When BidSpirit API returns 0 lots (catalog not yet ready), the sync job now fails with an explicit error message, allowing the next webhook to create a fresh retry job.
- Expanded CDN allowlist in pre_http_request filter — The HTTP filter during bulk post insertion now allows all
*.bidspirit.comsubdomains and BidSpirit image CDNs (fastly.net,cloudfront.net). Previously onlybidspirit.comandwww.bidspirit.comwere allowed, blocking image downloads during sync and causing worker hangs. - InsertLotsBS timeout guard — Stage 5 (InsertLotsBS processing loop) now has a 180-second timeout and logs progress every 2 batches. Prevents indefinite hangs that previously required manual force-kill.
- fixResult() no longer marks lots as done when postId=0 — When
lotProcessing()fails to create a WP post, the staging row now keepssyncFinished=0so the lot is retried on the next sync pass, instead of being permanently marked as complete with no actual post. - lotProcessing() logs error on missing auction term — Previously returned 0 silently when
Auction::findAuctionById()failed. Now logs an explicit error that feeds intofixResult()to keep the lot retryable. - Hourly orphan detection in safety cron — New step in
syncSafety.phpdetects lot posts that exist inbp_meta_databut are missing their auction taxonomy assignment (caused by workers killed mid-batch) and auto-repairs them withwp_set_object_terms().
Files Changed
- Modified:
inc/controllers/AuctionsAPI.php,inc/sync/CatalogSyncWorker.php,inc/abs/InsertLotsAbstract.php,inc/import/InsertLotsBS.php,crontasks/syncSafety.php
---
[3.2.4] — 2026-03-18
Sync Worker Hang Fix
Fixes
- Sync workers hanging at InsertLotsBS stage — Third-party plugins (Smush Pro, SmartCrawl SEO, WPMU DEV Updates) hook into
wp_insert_post()and make blocking outbound HTTPS calls for every lot processed. With 489+ lots per auction, this caused workers to hang indefinitely on socket reads to WPMU DEV servers (32.193.94.25,32.193.93.106). AddedWP_IMPORTINGconstant at the REST worker entry point and apre_http_requestfilter inCatalogSyncWorkerthat blocks all non-essential external HTTP during the batch post-insertion phase. Loopback (127.0.0.1,localhost) and BidSpirit API calls remain allowed. - Stuck staging rows after force-kill — When workers were force-killed mid-sync, staging rows in
import_historywere left withsyncstart=1and never unblocked. Subsequent sync runs could not see these rows (filtered out byLot::getRawLots()), causing the InsertLotsBS loop to exit immediately with 0 posts processed. Combined with job deduplication (SyncQueue::enqueue()skips if aprocessingjob exists), this created a deadlock where no new sync could proceed.
Files Changed
- Modified:
auctionforge.php,inc/sync/CatalogSyncWorker.php
---
[3.2.2] — 2026-03-17
Full Sync Auction Discovery Fix
Fixes
- Full Sync finds no auctions on fresh sites — The v3
full_syncaction only queried the WordPress database for existing auction terms, but on a freshly deployed site the database has zero auctions. AddedAuctionList::init()discovery step before querying the DB, so Full Sync now fetches all auctions from the BidSpirit API and creates taxonomy terms first, then enqueues catalog sync jobs for each.
Files Changed
- Modified:
auctionforge.php
---
[3.2.0] — 2026-03-14
Webhook Pipeline Fixes, Archive Sync & Admin UI Overhaul
New Features
- Archive Sync — New "Archive Sync" button on Sync Status admin page. Enqueues catalog sync jobs for all ARCHIVED/ENDED auctions. Past auctions now appear in the auction dropdown with an optgroup separator and state label.
- Sync Tasks v3 — Replaced old v2 task cards (importData, importBidSpirit, lotBidSpiritOld) with v3 queue-based tasks. "Sync Active Auctions" and "Sync Archived Auctions" now enqueue jobs via the queue system. Maintenance tasks (Clean Draft/Trash Lots, Clean Orphaned Meta) remain as direct-execution tasks.
- How It Works guide rewritten — Complete rewrite of the admin guide for v3 architecture. Documents webhook-first flow, all 5 job types, queue system mechanics, cron setup (external + WP-Cron), configuration constants, and troubleshooting.
Fixes
- Dual-write removed — Removed legacy handlers from
auctionCatalogUpdated(),auctionDayEnded(), anditemsUpdated()webhook methods. The old handlers were racing with the v3 worker, creating orphaned staging rows inimport_historythat were never processed. All three methods now exclusively use the v3 enqueue → spawn path. - ITEMS_UPDATED webhook — Fixed
itemsUpdated()failing to enqueue jobs. TheITEMS_UPDATEDpayload hasauctionIdnested initemsByLanguage.{lang}[0].item.auctionId, not at the top level. Added extraction logic to resolve it. - ItemUpdateWorker incomplete —
ItemUpdateWorker::process()was only callingLot::bulkSave()(staging table) without runningInsertLotsBSto process staged data into WP posts andbp_meta_data. Added the InsertLotsBS processing step with autocommit restore. Item updates now flow: stage → InsertLotsBS → WP post + meta → cache clear. - Worker spawn reliability — Changed
SyncQueue::spawnWorker()from non-blocking HTTPS to blocking HTTP loopback (http://127.0.0.1with explicitHostheader, 2s timeout). Fixes nginx 403/404 errors when HTTPS loopback hits the default vhost instead of the site's vhost. - API token constant — Plugin expects
AUCTIONFORGE_API_TOKENinwp-config.php(renamed fromUCO_API_TOKENduring the plugin rename). Documented in readme.
Database
- DB version: 22 → 23
Files Changed
- Modified:
inc/controllers/AuctionsAPI.php,inc/sync/ItemUpdateWorker.php,inc/sync/SyncQueue.php,auctionforge.php,admin/view/sync-status.php,readme.txt
---
[3.0.0] — 2025-03-14
New Feature: Webhook-First Sync Architecture (Sync v3)
Overview: Complete redesign of the BidSpirit data synchronisation pipeline. Replaces the old two-phase polling system (importBidSpirit every hour + importData every minute) with a webhook-driven job queue that processes data in near real-time.
Architecture
- 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: webhook → queue → background worker → WordPress posts. - Dual-write mode — During transition, webhooks enqueue jobs AND still run the legacy handlers. Once verified, legacy handlers can be removed cleanly.
- Job deduplication — Prevents duplicate work by checking for existing pending/processing jobs with the same auction_id + job_type.
New Components
- Job Queue System (
inc/sync/SyncQueue.php) — Priority-based FIFO queue with atomic job claiming, status tracking (pending/processing/completed/failed/skipped), worker PID tracking, and automatic stuck job recovery. - Sync Logger (
inc/sync/SyncLogger.php) — Real-time log table for admin console polling with level filtering (info/success/warning/error) and incremental cursor-based retrieval. - Catalog Sync Worker (
inc/sync/CatalogSyncWorker.php) — Processes catalog_sync, full_sync, and day_ended jobs by reusing existingLotList::singleRun()logic. - Item Update Worker (
inc/sync/ItemUpdateWorker.php) — Processes individual item_update jobs with the same logic as the webhookitemsUpdatedhandler. - Background Worker (
crontasks/syncWorker.php) — Async CLI process spawned by webhooks viaexec()or by the safety cron. Claims and processes queued jobs with a configurable timeout (default 240s). - Safety Net (
crontasks/syncSafety.php) — Hourly cron that resets stuck jobs (>10min), spawns workers for pending jobs, runs a 24-hour health check (auto-enqueues full sync if no webhooks received), and purges old data.
Admin UI
- Queue Status Dashboard — New card on Sync Status page showing pending/processing/completed/failed/skipped counts, recent jobs table with real-time refresh, worker status badge, and action buttons:
- Full Sync — Enqueues catalog sync for all active auctions
- Sync Selected — Enqueue a single auction from dropdown
- Spawn Worker — Manually trigger a background worker process
- Live Console — Dark-themed terminal console on the Sync Status page. Polls
af_sync_logevery 1.5s showing timestamped, color-coded log entries from webhooks, workers, queue operations, and the safety cron. Supports pause, clear, and auto-scroll.
Cron Changes
- Removed
importData(ran every minute — ~1,440 PHP executions/day) - Removed
importBidSpirit(ran hourly — ~24 PHP executions/day) - Added
syncSafety(runs hourly at :10 — 24 PHP executions/day) - Net effect: ~62 PHP executions/hour → 1 PHP execution/hour
- WP-Cron safety hook (
auctionforge_sync_safety) — Always-active hourly event, independent of external cron - setup.sh v3 — Updated task definitions, new
migratecommand for interactive v2→v3 transition
Database
- New table:
af_sync_queue— Job queue with status, priority, source, attempts, worker PID, timing columns - New table:
af_sync_log— Real-time log entries with context, level, auction_id, job_id - DB version: 20 → 22
Constants Added
| Constant | Default | Description |
|---|---|---|
|
AUCTIONFORGE_SYNC_WORKER_TIMEOUT| 240 | Worker process timeout in seconds ||
AUCTIONFORGE_SYNC_STALE_JOB| 600 | Seconds before a processing job is considered stuck ||
AUCTIONFORGE_SYNC_HEALTH_CHECK| 86400 | Seconds without webhook before triggering full sync ||
AUCTIONFORGE_SYNC_LOG_RETENTION| 7 | Days to keep log entries ||
AUCTIONFORGE_SYNC_QUEUE_RETENTION| 30 | Days to keep completed queue jobs ||
AUCTIONFORGE_CURL_TIMEOUT| 30 | BidSpirit API cURL timeout in seconds ||
AUCTIONFORGE_PHP_BINARY| /www/server/php/83/bin/php | PHP CLI binary path for spawning workers |AJAX Handlers Added
auctionforge_sync_log_poll— Incremental log polling for live consoleauctionforge_sync_queue_status— Queue counts + recent jobs for dashboardauctionforge_sync_enqueue— Admin-triggered sync actions (full_sync, sync_auction, spawn_worker)
Fixes
- cURL timeout — BidSpiritRequest now enforces a 30-second timeout (was unlimited/0), preventing hung connections from blocking the sync pipeline.
Files Changed
- Modified:
auctionforge.php,inc/coreIncludes.php,inc/controllers/AuctionsAPI.php,inc/BidSpiritRequest.php,admin/view/sync-status.php,crontasks/setup.sh - Created:
inc/sync/SyncQueue.php,inc/sync/SyncLogger.php,inc/sync/CatalogSyncWorker.php,inc/sync/ItemUpdateWorker.php,crontasks/syncWorker.php,crontasks/syncSafety.php
---
[2.7.3.0]
Fixes
- Various stability improvements and bug fixes.
[2.7.1.2]
Fixes
- Added missing
vatAndCommission()function inloadBid()— the sales tax display on single lot pages was never being rendered because the code to callloadTemplateforvat-and-commission-templatewas missing fromapp.js.
[2.7.1.1]
Fixes
- 2 decimal places now only appear in the bid modal (Your max bid, Total Price) via
showDecimalsflag. 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.
[2.7.0.9]
Fixes
- Fixed fatal error during plugin install/upgrade:
class-stats-database.phprequire failure.
[2.7.0.0]
New Features: Advanced Lot Analytics
- Conversion Tracking, Peak Viewing Times, Pre-Sale vs Live Comparison, Category Performance, Share Analytics, Search → View Funnel, Click-Through Tracking, CSV Export, Hot Lot Badge.
- New DB table:
af_lot_shares. New columns onaf_lot_analytics. DB version bumped to 20.
[2.6.0.0]
New Feature: Lot Analytics
- Comprehensive lot view and favorite tracking system with admin dashboard.
[2.5.0.0]
New Features
- Site Statistics System — Full website analytics built into the plugin admin.
- Recently Viewed Items — Profile page tab showing last 20 viewed lots per user.
- New private helper
-
v3.6.2.8 Stable Apr 30, 2026Download v3.6.2.8📦 9.23 MB⚙️ WP 5.2+🔧 PHP 7.2+✓ Tested 6.4
[3.6.2.8] — 2026-04-30
Suppress alerts for transient retry conditions
Why
The "BidSpirit API returned 0 lots — catalog may not be ready yet" message is logged when the BidSpirit webhook fires before the auction catalog is fully published. The safety cron retries the job automatically and it usually succeeds on the next attempt — there's no operator action required, so a Telegram alert is just noise.
Fix
- New private helper
SyncLogger::isSuppressedFromAlerts($message, $context)matches the message against a substring allowlist of known-transient errors. When matched, the row is still inserted intoaf_sync_log(so the in-app sync console still shows the retry chain) but theauctionforge_sync_error_loggedfan-out action does NOT fire — wpdeploy and Telegram stay quiet. - Default suppression substrings:
"BidSpirit API returned 0 lots","catalog may not be ready yet". - Extendable via the new
auctionforge_sync_alert_suppress_patternsfilter — themes/MU plugins can add their own substrings.
Files Changed
- Modified:
auctionforge.php,inc/sync/SyncLogger.php
---
- New private helper
-
v3.6.2.7 Stable Apr 30, 2026Download v3.6.2.7📦 9.23 MB⚙️ WP 5.2+🔧 PHP 7.2+✓ Tested 6.4
[3.6.2.7] — 2026-04-30
Typo fix
- Settings → Connections tab: the placeholder/help text under the Server field showed
https://my-accaunt.bidspirit.com/(extra "a"). Now readshttps://my-account.bidspirit.com/.
Files Changed
- Modified:
auctionforge.php,inc/controllers/Settings.php
---
- Settings → Connections tab: the placeholder/help text under the Server field showed
-
v3.6.2.6 Stable Apr 30, 2026Download v3.6.2.6📦 9.23 MB⚙️ WP 5.2+🔧 PHP 7.2+✓ Tested 6.4
[3.6.2.6] — 2026-04-30
Fix stale
plugin_versionin reportsWhy
Sites were reporting their old version to wpdeploy long after they'd been upgraded — e.g. Lonsdale Auctioneers ran v3.6.1.1 but kept telling wpdeploy it was on v2.9.6. Root cause: the constant
AUCTIONFORGE_VERSIONis read from the plugin file'sVersion:header *once at plugin load*, then frozen into$this->current_versionon the auto-updater instance. After a plugin upgrade replaces the file on disk, existing PHP-FPM workers keep using the cached constant value until they're recycled, so every report from those workers carries the old version.Fix
- New helper
AuctionForge_Auto_Updater::get_live_version()reads the version directly from the plugin file's header on each call (viaget_file_data()— uncached). report_health,push_sync_error_immediate, andretry_sync_errorsnow sendget_live_version()instead of the cached constant.- The pre-existing iteration through active plugins inside
report_healthalready usedget_plugin_data()per plugin, so secondary plugin entries were already accurate; only the top-levelplugin_versionfield was stale.
Files Changed
- Modified:
auctionforge.php,inc/class-auto-updater.php
---
- New helper
-
v3.6.2.5 Stable Apr 30, 2026Download v3.6.2.5📦 9.22 MB⚙️ WP 5.2+🔧 PHP 7.2+✓ Tested 6.4
[3.6.2.5] — 2026-04-30
Real diagnostics for plugin self-updates
Why
The wpdeploy
update_queuetable had a 46% historical failure rate, but every single failure row stored the literal string"Installation failed"— collapsing every failure mode into one opaque error with no diagnostic value. Root cause: theinstall_update()method in both clients (AF auto-updater and wpd-client) treatedPlugin_Upgrader::upgrade()as a boolean, throwing awayWP_Errorobjects and skin-emitted error messages.Fixes (
inc/class-auto-updater.phpinstall_update())- Refreshes the
update_pluginstransient before invoking the upgrader. The upgrader reads from this transient to know what version to download; if WP hasn't checked recently, the upgrader silently returns false (looking like a failure even though there's a real update queued at wpdeploy). - Distinguishes
WP_Error,false/null, and success.WP_Errorwas previously treated as truthy → reported as "completed" even on failure. Now extracts the error code and message. - Reads
Automatic_Upgrader_Skin::get_errors()to surface the real upgrader-emitted error messages. - Reads
$upgrader->resultwhich holds the finalWP_Errorfor some failure paths. - Captures PHP errors/warnings emitted during the upgrade (file-move issues, etc.) via a temporary
set_error_handler. - Detects "no update in transient" as a distinct failure cause and labels it explicitly so we know it's a transient-cache problem, not an actual install failure.
- Truncates the combined diagnostic to 1000 chars before sending.
The same fix is applied to
wpd-client.php(the WPD client plugin shipped fromclient-plugin/wpd-client.phpon the wpdeploy server).Files Changed
- Modified:
auctionforge.php,inc/class-auto-updater.php
---
- Refreshes the
-
v3.6.2.4 Stable Apr 30, 2026Download v3.6.2.4📦 9.22 MB⚙️ WP 5.2+🔧 PHP 7.2+✓ Tested 6.4
[3.6.2.4] — 2026-04-30
Bulk-sync worker dispatch fix
Fixes
- The HTTP-loopback worker (
auctionforge_rest_sync_workerinauctionforge.php) had its own switch statement for job-type dispatch, distinct from the one incrontasks/syncWorker.php. The newfull_sync_upcomingandfull_sync_pastjob types were only added to the CLI worker, so the loopback path produced "Unknown job type" errors. Both switches now route those types toBulkSyncWorker::process. inc/coreIncludes.phpnowrequire_oncesBulkSyncWorker.phpso the class is available wherever sync code runs.
Files Changed
- Modified:
auctionforge.php,inc/coreIncludes.php
---
- The HTTP-loopback worker (
-
v3.6.2.3 Stable Apr 30, 2026Download v3.6.2.3📦 9.22 MB⚙️ WP 5.2+🔧 PHP 7.2+✓ Tested 6.4
[3.6.2.3] — 2026-04-30
Fixes for end-to-end Telegram round-trip
Fixes
verify_api_keyreads the option fresh on every call (hash_equalsagainstget_option('auctionforge_update_api_key')) instead of relying on the cached$this->api_keyfrom constructor time. Different FPM workers can hold different cached values when the option drifts (e.g. via auto-heal collisions), which previously produced intermittent 401s on REST endpoints.- New REST endpoint
POST /wp-json/auctionforge/v1/sync/version— wraps the existingtrigger-installflow with a JSON response (always HTTP 200 withsuccessflag). The original endpoint returnedWP_Error('no_update', …, status: 404)when the plugin was already on the latest version, which nginx'serror_page 404directive then clobbered with a static HTML 404 page on hosts using aaPanel/BTWAF. Keeping the URL under/sync/*matches the pattern that's already proven to pass through host WAFs.
Files Changed
- Modified:
auctionforge.php,inc/class-auto-updater.php
---
-
v3.6.2.2 Stable Apr 29, 2026Download v3.6.2.2📦 9.22 MB⚙️ WP 5.2+🔧 PHP 7.2+✓ Tested 6.4
[3.6.2.2] — 2026-04-29
Catalog-sync kind disambiguation
Fix
catalog_syncjobs target a single auction that may be either active or archived. Until now their alerts were always classified askind=upcoming. The classifier now resolves the auction'sauction_stateterm meta and routes:ARCHIVED/ENDED/POST_AUCTION→kind=past→ Kill + Full Past buttons- anything else (or unresolvable) →
kind=upcoming→ Kill + Full Upcoming buttons
Files Changed
- Modified:
auctionforge.php,inc/class-auto-updater.php
---
-
v3.6.2.1 Stable Apr 29, 2026Download v3.6.2.1📦 9.22 MB⚙️ WP 5.2+🔧 PHP 7.2+✓ Tested 6.4
[3.6.2.1] — 2026-04-29
Telegram Sync Monitoring follow-ups
Features
- Context-aware alert buttons. Each Telegram alert now shows the action set most relevant to the failing sync: upcoming-sync errors get Kill + Full Upcoming, past-sync errors get Kill + Full Past, everything else gets Kill only. Button choice is driven by a new
kindfield classified at log-write time from the queue'sjob_type. - Plugin version in alerts + Update button. Each push now includes the live
plugin_version. wpdeploy compares it to the latestis_stable=1row in itsversionstable and only renders an Update plugin button when the site is behind. Tapping Update calls the existingPOST /wp-json/auctionforge/v1/trigger-installendpoint to force the upgrade.
Architecture
- New private helper
AuctionForge_Auto_Updater::classify_error_kind($jobId)looks up the job'sjob_typeand maps it to'upcoming'/'past'/'other'. Used by both the immediate push and the 1-min retry cron. - Outbound payloads now include
plugin_versionat the top level; wpdeploy refreshessites.plugin_versionon every/sync-errorsPOST.
Files Changed
- Modified:
auctionforge.php,inc/class-auto-updater.php
---
- Context-aware alert buttons. Each Telegram alert now shows the action set most relevant to the failing sync: upcoming-sync errors get Kill + Full Upcoming, past-sync errors get Kill + Full Past, everything else gets Kill only. Button choice is driven by a new
-
v3.6.2.0 Stable Apr 29, 2026Download v3.6.2.0📦 9.22 MB⚙️ WP 5.2+🔧 PHP 7.2+✓ Tested 6.4
[3.6.2.0] — 2026-04-29
Telegram Sync Monitoring & Remote Control
Features
- Instant Telegram alerts on sync errors. Any
level='error'row written toaf_sync_logis pushed (fire-and-forget, non-blocking) to wpdeploy, which fans it out to a configured Telegram group with inline-keyboard action buttons (Kill / Full Upcoming / Full Past / Acknowledge). - Remote command surface. Any group admin can tap a button to:
- Kill sync — flips DB flags via
SyncQueue::cancelAll(), then SIGTERMs every active worker; a 5-second watchdog escalates to SIGKILL for any survivor. - Full sync upcoming — full re-import of every active auction and its lots (queued, observable, killable). Replaces the
re-sync?do=importBidSpiritUpcomingflow with a queued equivalent. - Full sync past — same, for archived auctions.
- Safety-net retry cron (
auctionforge_retry_sync_errors, every minute) re-pushes recent error rows. wpdeploy dedupes viaUNIQUE(site_id, af_log_id)so duplicates are silent.
Architecture
SyncLogger::log()now firesdo_action('auctionforge_sync_error_logged', …)onlevel='error'so any handler can react. The auto-updater listener does a 2 s non-blocking POST to/api.php/sync-errors.- New REST endpoint
POST /wp-json/auctionforge/v1/sync/cancel-all(X-API-Key auth) — runsSyncQueue::cancelAll()+ SIGTERM + watchdog. Logs every action throughSyncLogger. POST /sync/startextended with amodeparameter (upcomingdefault,pastfor archived). Bulk re-sync is now a queued job, not a synchronous block.- New job types
full_sync_upcomingandfull_sync_pastonSyncQueue, dispatched to a newBulkSyncWorkerthat wraps the existingAuctionList::init()+LotList::init($upcoming)pipeline. syncWorker.phpinstalls a SIGTERM handler that flips the in-flight job tofailedwith a "Killed by admin (SIGTERM, cleanup OK)" marker and closes the DB cleanly before exiting. Watchdog escalates to SIGKILL after 5 s grace.LotList::auctionProcessing()now heartbeats the active bulk-sync job between auctions, preventing the safety cron from auto-failing long bulk runs as stale (the 600 s threshold is unchanged).
Files Changed
- Modified:
auctionforge.php,inc/sync/SyncLogger.php,inc/sync/SyncQueue.php,inc/class-auto-updater.php,crontasks/syncWorker.php,inc/import/LotList.php - Created:
inc/sync/BulkSyncWorker.php
---
- Instant Telegram alerts on sync errors. Any
-
v3.6.1.6 Stable Apr 29, 2026Download v3.6.1.6📦 9.22 MB⚙️ WP 5.2+🔧 PHP 7.2+✓ Tested 6.4
[3.6.1.6] — 2026-04-29
High-Value Lot Modes for
[bp_lot_list]Features
high_value_pastmode — Displays past auction lots ordered by their catalog estimate (estimatedPriceInt), highest first. Useful for "Top Lots" or "Highlights" sections.high_value_soldmode — Displays past sold lots ordered by their actual sold price (soldBid), highest first. Only includes genuinely sold lots (soldBid > 0) and reuses the same false-positive guard asrandom_pastto skip lots wheresoldBidwas carried over fromstartPricewithout real bidding activity.- Admin documentation updated — The Shortcodes reference page in WP Admin now lists both new modes in the
modeattribute description and includes example shortcode usage.
Architecture
- New constants
MODE_HIGH_VALUE_PASTandMODE_HIGH_VALUE_SOLDonLotsWidget. - New method
LotsWidget::getLotListHighValue($mode, $limit)builds the query, applies the past-auction tax filter, setsbp_orderbyto the relevant meta field withDESCorder, and (for the sold variant) filters out unsold-but-stale lots in PHP. - New filter hook
bp_lot_list_high_value_args_filterfor downstream customization of the WP_Query args.
Files Changed
- Modified:
inc/widgets/LotsWidget.php,inc/controllers/ShortcodesPage.php
---
-
v3.6.1.5 Stable Apr 29, 2026Download v3.6.1.5📦 8.95 MB⚙️ WP 5.2+🔧 PHP 7.2+✓ Tested 6.4
AuctionForge Changelog
All notable changes to the AuctionForge plugin are documented in this file.
---
[3.6.0.18] — 2026-04-25
Brevo SMS Notifications Integration
Features
- Transactional SMS via Brevo API — The plugin now sends text message alerts through the Brevo transactional SMS service, running alongside existing Firebase push notifications.
- Four Notification Types:
- New Auction Published — Broadcast SMS to all opted-in subscribers when an auction is published.
- Auction Starting Soon — Targeted SMS to users registered for an auction when it is about to start.
- Favorited Item Live Soon — Targeted SMS to users who favorited a lot when it is approaching in the auction.
- Outbid Notice — SMS sent when a user's leading bid is surpassed, with a 5-minute per-item cooldown to prevent spam.
- SMS Subscriber Database — New
af_sms_subscriberstable stores user phone numbers, country codes, and per-notification-type opt-in preferences (GDPR-ready explicit consent). - Admin Settings Tab — New "SMS Notifications" tab in Settings with:
- Brevo API Key input
- SMS Sender Name (11 char max)
- Master enable/disable toggle
- Per-notification-type on/off switches
- Test SMS widget with phone input and send button
- Live subscriber count display
- Profile SMS Preferences — Users can opt into SMS notifications directly from their profile page with phone number entry and granular notification type selection.
Architecture
- BrevoSMS Service (
inc/services/BrevoSMS.php) — cURL-based API wrapper with broadcast, targeted, and single-send methods, message builders with 160-char limit awareness, rate limiting, and comprehensive error logging. - SMSSubscriber Model (
inc/model/SMSSubscriber.php) — CRUD operations, email-to-phone resolution, opt-in filtering, and upsert logic. - Webhook Integration — SMS dispatch hooks added to
AuctionsAPI.phpmethods:leading_bid_surpassed(),item_live_soon(),auction_starts_soon(), andauctionPublishedPush().
AJAX Handlers
auctionforge_sms_save— Save SMS preferences from profile pageauctionforge_sms_load— Load SMS preferences for profile pageauctionforge_sms_test— Admin-only test SMS endpoint
Database
- New table:
af_sms_subscribers— Phone numbers, country codes, per-notification opt-ins, timestamps
Files Changed
- Modified:
auctionforge.php,inc/coreIncludes.php,inc/controllers/AuctionsAPI.php,inc/controllers/Settings.php,admin/view/settings.php,templates/parts/profile-templates.php - Created:
inc/services/BrevoSMS.php,inc/model/SMSSubscriber.php
---
[3.6.0.7] — 2026-04-14
Hotfix
Fixes
- Namespace resolution — Fixed fatal error in
wp_footercommission label hook caused by unqualifiedSettingsHelperandSettingsclass references. Now uses fully qualified namespaces.
Files Changed
- Modified:
auctionforge.php
---
[3.6.0.6] — 2026-04-14
Commission Label Override Fix
Fixes
- Theme template override compatibility — Moved the commission label JS override from the
single-lot.phptemplate intoauctionforge.phpviawp_footerhook (priority 99). Sites with theme-level template overrides (e.g.themes/*/auctionforge/single-lot.php) were not picking up the inline script. Thewp_footerapproach works universally on all single lot pages.
Files Changed
- Modified:
auctionforge.php,templates/single-lot.php
---
[3.6.0.5] — 2026-04-14
Commission Label Override
Features
- Commission Label Setting — New dropdown in Settings → Appearance allowing admins to choose between "Buyer's Premium" (default) and "Auction House Commission" as the label displayed on lot pages. This overrides the Bidspirit JS client's default label using a MutationObserver that catches asynchronously injected text.
Files Changed
- Modified:
inc/controllers/Settings.php,templates/single-lot.php
---
[3.6.0.4] — 2026-04-12
Auction Approval Modal Redesign
Changes
- Removed BidSpirit Terms of Use — The generic BidSpirit "Terms of Use" section that appeared at the top of the non-credit-card approval modal has been removed. The modal now shows only the auction house's own legal agreements managed within the plugin.
- Renamed Modal Title — Changed "Terms of conditions" to "Terms & Conditions".
- Larger Scroll Area — The Terms & Conditions scroll box is now 350px tall (up from 200px) for easier reading.
- Proportional Section Heights — Refund & Return Policy and Chargeback Waiver sections use a shorter 260px scroll box to visually distinguish them from the primary Terms & Conditions.
Files Changed
- Modified:
templates/js-chunks/approval-info.php,assets/js/app.js
---
[3.6.0.2] — 2026-04-10
Webhook Token Generator
Features
- Token Generator Widget — Added a 16-character random token generator directly below the "Webhook auth token" field on the Settings page. Includes a "Generate Token" button and a clipboard copy icon with visual feedback.
Files Changed
- Modified:
inc/controllers/Settings.php
---
[3.6.0.1] — 2026-04-10
Patch
Changes
- Version bump.
---
[3.6.0.0] — 2026-04-10
Legal Agreements for Auction Approval
Features
- Terms & Conditions — A mandatory, scrollable Terms & Conditions document is now displayed during the auction approval process. Bidders must scroll to the bottom and check an agreement box before their approval request is submitted. Always enabled.
- Refund & Return Policy — An optional, scrollable Refund & Return Policy can be enabled in Settings. When enabled, bidders must read and accept it during auction approval.
- Chargeback Waiver — An optional, scrollable Chargeback Waiver can be enabled in Settings. When enabled, bidders must read and accept it during auction approval.
- Admin Management — New "Legal Agreements" page under the Bidspirit admin menu with tabbed TinyMCE editors for each agreement type. Includes automatic version numbering (incremented on content change) and full version history.
- Consent Logging — Every agreement acceptance is logged to a dedicated database table (
af_user_agreement_log) with the agreement type, version, user email, IP address, user agent, auction ID, and timestamp. - User Tracking Integration — Agreement events (
terms_agreement,refund_agreement,chargeback_waiver) are also recorded in the existing IP tracking system alongside registration, login, and bid events. - Placeholder Content — Default sample content is seeded on plugin activation for all three agreement types.
Settings Added
- Enable Refund & Return Policy — Toggle to require bidders to accept the refund policy during auction approval.
- Enable Chargeback Waiver — Toggle to require bidders to accept the chargeback waiver during auction approval.
Database
- New table:
af_legal_agreements— Current active agreement content per type - New table:
af_legal_agreement_versions— Version history archive - New table:
af_user_agreement_log— User consent records
Files Changed
- Modified:
auctionforge.php,inc/controllers/Settings.php,inc/controllers/BidspiritViews.php,inc/ip-logger.php,templates/js-chunks/approval-info.php,assets/js/app.js - Created:
inc/legal/class-legal-agreements.php,admin/view/legal-agreements.php
---
[3.5.0.6] — 2026-04-08
Bid Event Tracking
Features
- Bid Tracking — All successful bids (regular, catalog, pre-sale buyout, post-sale purchase) now fire
afLogIP("bid", bidspiritUser)to capture the bidder's full identity in the user tracking table. - Whitelist Update — Added
bidto the allowedevent_typevalues in both the local plugin and the central WPDeploy API.
---
[3.5.0.5] — 2026-04-08
Self-Healing Database Schema
Features
- Auto-Migration — The plugin now auto-detects and adds any missing tracking table columns on version upgrade, ensuring sites with older schemas seamlessly migrate without manual SQL.
---
[3.5.0.4] — 2026-04-08
API Key Auto-Healing
Features
- Seamless Self-Registration — The WordPress plugin now autonomously regenerates and saves a fresh API Key whenever WPDeploy rejects a payload with an
api_key_collisionerror. This guarantees zero-downtime security handovers when developers clone instances to proxy/staging servers.
---
[3.5.0.3] — 2026-04-08
API Key Collision Defense
Features
- 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_collisionerrors, directly instructing developers to update cloned keys.
---
[3.5.0.2] — 2026-04-08
Modal Trigger Hotfix
Fixes
- Restructured internal UI rendering priority to gracefully deploy the inline Modal triggers inside custom IP log view without colliding with cached
z-indexstacks.
---
[3.5.0.1] — 2026-04-08
Hotfix
Fixes
- Timed Auction Badge Visibility — Fixed a strict type-matching bug in the main
auction_list.phpcore file that incorrectly hid the "Timed Auction" badge overlay from valid timed/online auctions on the main upcoming/archive views. The badge now displays properly across all manual and Bidspirit-synced objects when toggled on.
Files Changed
- Modified:
templates/main/auction_list.php
---
[3.2.9.1] — 2026-03-30
Timed Auction Display Enhancements
Features
- Timed Auction Countdown Text Toggle — Added a WP-Admin setting "Change text to 'Auction will close in'" that conditionally changes the countdown label for timed/online auctions on single lot pages.
- Shortcode Text Toggle Support — Extended the new countdown text logic to the
bp_upcoming_wideshortcodes so "Live bidding starts in:" successfully transitions to "Auction will close in:" for timed auctions.
Files Changed
- Modified:
inc/controllers/Settings.php,templates/single-lot.php,templates/shortcodes/upcoming-auction-wide.php,templates/shortcodes/upcoming-auction-wide-manual.php
---
[3.2.9.0] — 2026-03-29
Billing & Invoices Polish
Fixes
- Profile Invoice ID Tracking — Prevented internal auction codes (e.g.
002orai4) from breaking into the clean hyphenated titles inside theprofile-templates.phpview. - Dynamic Payment Statuses — Replaced Bidspirit's default/cached
NOT PAIDHTML payloads by wiring thedompdfgenerator to directly respect the current$b.statusstring from the API (resolving instances where a paid invoice still printed "NOT PAID" atop the document). - Payment Instructions Conditional — Automatically hide the "Payment Instructions" block from the PDF footer when an invoice is fully paid.
- Improved Nomenclature — Changed "Invoice No:" to "Bidder No:" on document output to prevent confusion with static invoice ledger IDs.
---
[3.2.6.0] — 2026-03-28
Multi-Day Auction Lot Filtering Fix
Fixes
- Day 2+ showing lots from Day 1 in multi-day auctions — The
itemIndexcolumn inbp_meta_dataisvarchar(55), but the day-range filter inBidspiritQuery::bp_query_where()was comparing it as a string. With string comparison, lot numbers like'11','101'–'145'incorrectly fell between'1001'and'1450', causing Day 1 lots to leak into Day 2 results. Fixed by usingCAST(bpMeta.itemIndex AS UNSIGNED)for numeric comparison andintval()on the PHP-side boundary values. Letter lots (e.g.14A,1025A) are handled correctly —CASTstrips the suffix, keeping them grouped with their base lot number.
Files Changed
- Modified:
inc/controllers/BidspiritQuery.php
---
[3.2.5.9] — 2026-03-27
Catalog Page Fix
Fixes
- Duplicate preview hours on catalog pages — The
displayHoursfield was rendered twice: once via thebp_after_description_auctionhook inBidspiritViews.phpand once inline in the auction template. Removed the hook-based rendering to eliminate the duplication.
Files Changed
- Modified:
inc/controllers/BidspiritViews.php,templates/main/auction.php
---
[3.2.5] — 2026-03-19
Sync Reliability & Stuck Lot Prevention
Fixes
- CATALOG_PUBLISHED webhook now triggers catalog sync — Previously only sent push notifications without syncing lots. When the earlier AUCTION_CATALOG_UPDATED fired before the catalog was ready on BidSpirit, lots were never imported. CATALOG_PUBLISHED now calls
auctionCatalogUpdated()to trigger a full catalog sync when the catalog is actually available. - 0-lot API results now fail instead of silently succeeding — When BidSpirit API returns 0 lots (catalog not yet ready), the sync job now fails with an explicit error message, allowing the next webhook to create a fresh retry job.
- Expanded CDN allowlist in pre_http_request filter — The HTTP filter during bulk post insertion now allows all
*.bidspirit.comsubdomains and BidSpirit image CDNs (fastly.net,cloudfront.net). Previously onlybidspirit.comandwww.bidspirit.comwere allowed, blocking image downloads during sync and causing worker hangs. - InsertLotsBS timeout guard — Stage 5 (InsertLotsBS processing loop) now has a 180-second timeout and logs progress every 2 batches. Prevents indefinite hangs that previously required manual force-kill.
- fixResult() no longer marks lots as done when postId=0 — When
lotProcessing()fails to create a WP post, the staging row now keepssyncFinished=0so the lot is retried on the next sync pass, instead of being permanently marked as complete with no actual post. - lotProcessing() logs error on missing auction term — Previously returned 0 silently when
Auction::findAuctionById()failed. Now logs an explicit error that feeds intofixResult()to keep the lot retryable. - Hourly orphan detection in safety cron — New step in
syncSafety.phpdetects lot posts that exist inbp_meta_databut are missing their auction taxonomy assignment (caused by workers killed mid-batch) and auto-repairs them withwp_set_object_terms().
Files Changed
- Modified:
inc/controllers/AuctionsAPI.php,inc/sync/CatalogSyncWorker.php,inc/abs/InsertLotsAbstract.php,inc/import/InsertLotsBS.php,crontasks/syncSafety.php
---
[3.2.4] — 2026-03-18
Sync Worker Hang Fix
Fixes
- Sync workers hanging at InsertLotsBS stage — Third-party plugins (Smush Pro, SmartCrawl SEO, WPMU DEV Updates) hook into
wp_insert_post()and make blocking outbound HTTPS calls for every lot processed. With 489+ lots per auction, this caused workers to hang indefinitely on socket reads to WPMU DEV servers (32.193.94.25,32.193.93.106). AddedWP_IMPORTINGconstant at the REST worker entry point and apre_http_requestfilter inCatalogSyncWorkerthat blocks all non-essential external HTTP during the batch post-insertion phase. Loopback (127.0.0.1,localhost) and BidSpirit API calls remain allowed. - Stuck staging rows after force-kill — When workers were force-killed mid-sync, staging rows in
import_historywere left withsyncstart=1and never unblocked. Subsequent sync runs could not see these rows (filtered out byLot::getRawLots()), causing the InsertLotsBS loop to exit immediately with 0 posts processed. Combined with job deduplication (SyncQueue::enqueue()skips if aprocessingjob exists), this created a deadlock where no new sync could proceed.
Files Changed
- Modified:
auctionforge.php,inc/sync/CatalogSyncWorker.php
---
[3.2.2] — 2026-03-17
Full Sync Auction Discovery Fix
Fixes
- Full Sync finds no auctions on fresh sites — The v3
full_syncaction only queried the WordPress database for existing auction terms, but on a freshly deployed site the database has zero auctions. AddedAuctionList::init()discovery step before querying the DB, so Full Sync now fetches all auctions from the BidSpirit API and creates taxonomy terms first, then enqueues catalog sync jobs for each.
Files Changed
- Modified:
auctionforge.php
---
[3.2.0] — 2026-03-14
Webhook Pipeline Fixes, Archive Sync & Admin UI Overhaul
New Features
- Archive Sync — New "Archive Sync" button on Sync Status admin page. Enqueues catalog sync jobs for all ARCHIVED/ENDED auctions. Past auctions now appear in the auction dropdown with an optgroup separator and state label.
- Sync Tasks v3 — Replaced old v2 task cards (importData, importBidSpirit, lotBidSpiritOld) with v3 queue-based tasks. "Sync Active Auctions" and "Sync Archived Auctions" now enqueue jobs via the queue system. Maintenance tasks (Clean Draft/Trash Lots, Clean Orphaned Meta) remain as direct-execution tasks.
- How It Works guide rewritten — Complete rewrite of the admin guide for v3 architecture. Documents webhook-first flow, all 5 job types, queue system mechanics, cron setup (external + WP-Cron), configuration constants, and troubleshooting.
Fixes
- Dual-write removed — Removed legacy handlers from
auctionCatalogUpdated(),auctionDayEnded(), anditemsUpdated()webhook methods. The old handlers were racing with the v3 worker, creating orphaned staging rows inimport_historythat were never processed. All three methods now exclusively use the v3 enqueue → spawn path. - ITEMS_UPDATED webhook — Fixed
itemsUpdated()failing to enqueue jobs. TheITEMS_UPDATEDpayload hasauctionIdnested initemsByLanguage.{lang}[0].item.auctionId, not at the top level. Added extraction logic to resolve it. - ItemUpdateWorker incomplete —
ItemUpdateWorker::process()was only callingLot::bulkSave()(staging table) without runningInsertLotsBSto process staged data into WP posts andbp_meta_data. Added the InsertLotsBS processing step with autocommit restore. Item updates now flow: stage → InsertLotsBS → WP post + meta → cache clear. - Worker spawn reliability — Changed
SyncQueue::spawnWorker()from non-blocking HTTPS to blocking HTTP loopback (http://127.0.0.1with explicitHostheader, 2s timeout). Fixes nginx 403/404 errors when HTTPS loopback hits the default vhost instead of the site's vhost. - API token constant — Plugin expects
AUCTIONFORGE_API_TOKENinwp-config.php(renamed fromUCO_API_TOKENduring the plugin rename). Documented in readme.
Database
- DB version: 22 → 23
Files Changed
- Modified:
inc/controllers/AuctionsAPI.php,inc/sync/ItemUpdateWorker.php,inc/sync/SyncQueue.php,auctionforge.php,admin/view/sync-status.php,readme.txt
---
[3.0.0] — 2025-03-14
New Feature: Webhook-First Sync Architecture (Sync v3)
Overview: Complete redesign of the BidSpirit data synchronisation pipeline. Replaces the old two-phase polling system (importBidSpirit every hour + importData every minute) with a webhook-driven job queue that processes data in near real-time.
Architecture
- 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: webhook → queue → background worker → WordPress posts. - Dual-write mode — During transition, webhooks enqueue jobs AND still run the legacy handlers. Once verified, legacy handlers can be removed cleanly.
- Job deduplication — Prevents duplicate work by checking for existing pending/processing jobs with the same auction_id + job_type.
New Components
- Job Queue System (
inc/sync/SyncQueue.php) — Priority-based FIFO queue with atomic job claiming, status tracking (pending/processing/completed/failed/skipped), worker PID tracking, and automatic stuck job recovery. - Sync Logger (
inc/sync/SyncLogger.php) — Real-time log table for admin console polling with level filtering (info/success/warning/error) and incremental cursor-based retrieval. - Catalog Sync Worker (
inc/sync/CatalogSyncWorker.php) — Processes catalog_sync, full_sync, and day_ended jobs by reusing existingLotList::singleRun()logic. - Item Update Worker (
inc/sync/ItemUpdateWorker.php) — Processes individual item_update jobs with the same logic as the webhookitemsUpdatedhandler. - Background Worker (
crontasks/syncWorker.php) — Async CLI process spawned by webhooks viaexec()or by the safety cron. Claims and processes queued jobs with a configurable timeout (default 240s). - Safety Net (
crontasks/syncSafety.php) — Hourly cron that resets stuck jobs (>10min), spawns workers for pending jobs, runs a 24-hour health check (auto-enqueues full sync if no webhooks received), and purges old data.
Admin UI
- Queue Status Dashboard — New card on Sync Status page showing pending/processing/completed/failed/skipped counts, recent jobs table with real-time refresh, worker status badge, and action buttons:
- Full Sync — Enqueues catalog sync for all active auctions
- Sync Selected — Enqueue a single auction from dropdown
- Spawn Worker — Manually trigger a background worker process
- Live Console — Dark-themed terminal console on the Sync Status page. Polls
af_sync_logevery 1.5s showing timestamped, color-coded log entries from webhooks, workers, queue operations, and the safety cron. Supports pause, clear, and auto-scroll.
Cron Changes
- Removed
importData(ran every minute — ~1,440 PHP executions/day) - Removed
importBidSpirit(ran hourly — ~24 PHP executions/day) - Added
syncSafety(runs hourly at :10 — 24 PHP executions/day) - Net effect: ~62 PHP executions/hour → 1 PHP execution/hour
- WP-Cron safety hook (
auctionforge_sync_safety) — Always-active hourly event, independent of external cron - setup.sh v3 — Updated task definitions, new
migratecommand for interactive v2→v3 transition
Database
- New table:
af_sync_queue— Job queue with status, priority, source, attempts, worker PID, timing columns - New table:
af_sync_log— Real-time log entries with context, level, auction_id, job_id - DB version: 20 → 22
Constants Added
| Constant | Default | Description |
|---|---|---|
|
AUCTIONFORGE_SYNC_WORKER_TIMEOUT| 240 | Worker process timeout in seconds ||
AUCTIONFORGE_SYNC_STALE_JOB| 600 | Seconds before a processing job is considered stuck ||
AUCTIONFORGE_SYNC_HEALTH_CHECK| 86400 | Seconds without webhook before triggering full sync ||
AUCTIONFORGE_SYNC_LOG_RETENTION| 7 | Days to keep log entries ||
AUCTIONFORGE_SYNC_QUEUE_RETENTION| 30 | Days to keep completed queue jobs ||
AUCTIONFORGE_CURL_TIMEOUT| 30 | BidSpirit API cURL timeout in seconds ||
AUCTIONFORGE_PHP_BINARY| /www/server/php/83/bin/php | PHP CLI binary path for spawning workers |AJAX Handlers Added
auctionforge_sync_log_poll— Incremental log polling for live consoleauctionforge_sync_queue_status— Queue counts + recent jobs for dashboardauctionforge_sync_enqueue— Admin-triggered sync actions (full_sync, sync_auction, spawn_worker)
Fixes
- cURL timeout — BidSpiritRequest now enforces a 30-second timeout (was unlimited/0), preventing hung connections from blocking the sync pipeline.
Files Changed
- Modified:
auctionforge.php,inc/coreIncludes.php,inc/controllers/AuctionsAPI.php,inc/BidSpiritRequest.php,admin/view/sync-status.php,crontasks/setup.sh - Created:
inc/sync/SyncQueue.php,inc/sync/SyncLogger.php,inc/sync/CatalogSyncWorker.php,inc/sync/ItemUpdateWorker.php,crontasks/syncWorker.php,crontasks/syncSafety.php
---
[2.7.3.0]
Fixes
- Various stability improvements and bug fixes.
[2.7.1.2]
Fixes
- Added missing
vatAndCommission()function inloadBid()— the sales tax display on single lot pages was never being rendered because the code to callloadTemplateforvat-and-commission-templatewas missing fromapp.js.
[2.7.1.1]
Fixes
- 2 decimal places now only appear in the bid modal (Your max bid, Total Price) via
showDecimalsflag. 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.
[2.7.0.9]
Fixes
- Fixed fatal error during plugin install/upgrade:
class-stats-database.phprequire failure.
[2.7.0.0]
New Features: Advanced Lot Analytics
- Conversion Tracking, Peak Viewing Times, Pre-Sale vs Live Comparison, Category Performance, Share Analytics, Search → View Funnel, Click-Through Tracking, CSV Export, Hot Lot Badge.
- New DB table:
af_lot_shares. New columns onaf_lot_analytics. DB version bumped to 20.
[2.6.0.0]
New Feature: Lot Analytics
- Comprehensive lot view and favorite tracking system with admin dashboard.
[2.5.0.0]
New Features
- Site Statistics System — Full website analytics built into the plugin admin.
- Recently Viewed Items — Profile page tab showing last 20 viewed lots per user.
-
v3.6.1.3 Stable Apr 29, 2026Download v3.6.1.3📦 8.95 MB⚙️ WP 5.2+🔧 PHP 7.2+✓ Tested 6.4
AuctionForge Changelog
All notable changes to the AuctionForge plugin are documented in this file.
---
[3.6.0.18] — 2026-04-25
Brevo SMS Notifications Integration
Features
- Transactional SMS via Brevo API — The plugin now sends text message alerts through the Brevo transactional SMS service, running alongside existing Firebase push notifications.
- Four Notification Types:
- New Auction Published — Broadcast SMS to all opted-in subscribers when an auction is published.
- Auction Starting Soon — Targeted SMS to users registered for an auction when it is about to start.
- Favorited Item Live Soon — Targeted SMS to users who favorited a lot when it is approaching in the auction.
- Outbid Notice — SMS sent when a user's leading bid is surpassed, with a 5-minute per-item cooldown to prevent spam.
- SMS Subscriber Database — New
af_sms_subscriberstable stores user phone numbers, country codes, and per-notification-type opt-in preferences (GDPR-ready explicit consent). - Admin Settings Tab — New "SMS Notifications" tab in Settings with:
- Brevo API Key input
- SMS Sender Name (11 char max)
- Master enable/disable toggle
- Per-notification-type on/off switches
- Test SMS widget with phone input and send button
- Live subscriber count display
- Profile SMS Preferences — Users can opt into SMS notifications directly from their profile page with phone number entry and granular notification type selection.
Architecture
- BrevoSMS Service (
inc/services/BrevoSMS.php) — cURL-based API wrapper with broadcast, targeted, and single-send methods, message builders with 160-char limit awareness, rate limiting, and comprehensive error logging. - SMSSubscriber Model (
inc/model/SMSSubscriber.php) — CRUD operations, email-to-phone resolution, opt-in filtering, and upsert logic. - Webhook Integration — SMS dispatch hooks added to
AuctionsAPI.phpmethods:leading_bid_surpassed(),item_live_soon(),auction_starts_soon(), andauctionPublishedPush().
AJAX Handlers
auctionforge_sms_save— Save SMS preferences from profile pageauctionforge_sms_load— Load SMS preferences for profile pageauctionforge_sms_test— Admin-only test SMS endpoint
Database
- New table:
af_sms_subscribers— Phone numbers, country codes, per-notification opt-ins, timestamps
Files Changed
- Modified:
auctionforge.php,inc/coreIncludes.php,inc/controllers/AuctionsAPI.php,inc/controllers/Settings.php,admin/view/settings.php,templates/parts/profile-templates.php - Created:
inc/services/BrevoSMS.php,inc/model/SMSSubscriber.php
---
[3.6.0.7] — 2026-04-14
Hotfix
Fixes
- Namespace resolution — Fixed fatal error in
wp_footercommission label hook caused by unqualifiedSettingsHelperandSettingsclass references. Now uses fully qualified namespaces.
Files Changed
- Modified:
auctionforge.php
---
[3.6.0.6] — 2026-04-14
Commission Label Override Fix
Fixes
- Theme template override compatibility — Moved the commission label JS override from the
single-lot.phptemplate intoauctionforge.phpviawp_footerhook (priority 99). Sites with theme-level template overrides (e.g.themes/*/auctionforge/single-lot.php) were not picking up the inline script. Thewp_footerapproach works universally on all single lot pages.
Files Changed
- Modified:
auctionforge.php,templates/single-lot.php
---
[3.6.0.5] — 2026-04-14
Commission Label Override
Features
- Commission Label Setting — New dropdown in Settings → Appearance allowing admins to choose between "Buyer's Premium" (default) and "Auction House Commission" as the label displayed on lot pages. This overrides the Bidspirit JS client's default label using a MutationObserver that catches asynchronously injected text.
Files Changed
- Modified:
inc/controllers/Settings.php,templates/single-lot.php
---
[3.6.0.4] — 2026-04-12
Auction Approval Modal Redesign
Changes
- Removed BidSpirit Terms of Use — The generic BidSpirit "Terms of Use" section that appeared at the top of the non-credit-card approval modal has been removed. The modal now shows only the auction house's own legal agreements managed within the plugin.
- Renamed Modal Title — Changed "Terms of conditions" to "Terms & Conditions".
- Larger Scroll Area — The Terms & Conditions scroll box is now 350px tall (up from 200px) for easier reading.
- Proportional Section Heights — Refund & Return Policy and Chargeback Waiver sections use a shorter 260px scroll box to visually distinguish them from the primary Terms & Conditions.
Files Changed
- Modified:
templates/js-chunks/approval-info.php,assets/js/app.js
---
[3.6.0.2] — 2026-04-10
Webhook Token Generator
Features
- Token Generator Widget — Added a 16-character random token generator directly below the "Webhook auth token" field on the Settings page. Includes a "Generate Token" button and a clipboard copy icon with visual feedback.
Files Changed
- Modified:
inc/controllers/Settings.php
---
[3.6.0.1] — 2026-04-10
Patch
Changes
- Version bump.
---
[3.6.0.0] — 2026-04-10
Legal Agreements for Auction Approval
Features
- Terms & Conditions — A mandatory, scrollable Terms & Conditions document is now displayed during the auction approval process. Bidders must scroll to the bottom and check an agreement box before their approval request is submitted. Always enabled.
- Refund & Return Policy — An optional, scrollable Refund & Return Policy can be enabled in Settings. When enabled, bidders must read and accept it during auction approval.
- Chargeback Waiver — An optional, scrollable Chargeback Waiver can be enabled in Settings. When enabled, bidders must read and accept it during auction approval.
- Admin Management — New "Legal Agreements" page under the Bidspirit admin menu with tabbed TinyMCE editors for each agreement type. Includes automatic version numbering (incremented on content change) and full version history.
- Consent Logging — Every agreement acceptance is logged to a dedicated database table (
af_user_agreement_log) with the agreement type, version, user email, IP address, user agent, auction ID, and timestamp. - User Tracking Integration — Agreement events (
terms_agreement,refund_agreement,chargeback_waiver) are also recorded in the existing IP tracking system alongside registration, login, and bid events. - Placeholder Content — Default sample content is seeded on plugin activation for all three agreement types.
Settings Added
- Enable Refund & Return Policy — Toggle to require bidders to accept the refund policy during auction approval.
- Enable Chargeback Waiver — Toggle to require bidders to accept the chargeback waiver during auction approval.
Database
- New table:
af_legal_agreements— Current active agreement content per type - New table:
af_legal_agreement_versions— Version history archive - New table:
af_user_agreement_log— User consent records
Files Changed
- Modified:
auctionforge.php,inc/controllers/Settings.php,inc/controllers/BidspiritViews.php,inc/ip-logger.php,templates/js-chunks/approval-info.php,assets/js/app.js - Created:
inc/legal/class-legal-agreements.php,admin/view/legal-agreements.php
---
[3.5.0.6] — 2026-04-08
Bid Event Tracking
Features
- Bid Tracking — All successful bids (regular, catalog, pre-sale buyout, post-sale purchase) now fire
afLogIP("bid", bidspiritUser)to capture the bidder's full identity in the user tracking table. - Whitelist Update — Added
bidto the allowedevent_typevalues in both the local plugin and the central WPDeploy API.
---
[3.5.0.5] — 2026-04-08
Self-Healing Database Schema
Features
- Auto-Migration — The plugin now auto-detects and adds any missing tracking table columns on version upgrade, ensuring sites with older schemas seamlessly migrate without manual SQL.
---
[3.5.0.4] — 2026-04-08
API Key Auto-Healing
Features
- Seamless Self-Registration — The WordPress plugin now autonomously regenerates and saves a fresh API Key whenever WPDeploy rejects a payload with an
api_key_collisionerror. This guarantees zero-downtime security handovers when developers clone instances to proxy/staging servers.
---
[3.5.0.3] — 2026-04-08
API Key Collision Defense
Features
- 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_collisionerrors, directly instructing developers to update cloned keys.
---
[3.5.0.2] — 2026-04-08
Modal Trigger Hotfix
Fixes
- Restructured internal UI rendering priority to gracefully deploy the inline Modal triggers inside custom IP log view without colliding with cached
z-indexstacks.
---
[3.5.0.1] — 2026-04-08
Hotfix
Fixes
- Timed Auction Badge Visibility — Fixed a strict type-matching bug in the main
auction_list.phpcore file that incorrectly hid the "Timed Auction" badge overlay from valid timed/online auctions on the main upcoming/archive views. The badge now displays properly across all manual and Bidspirit-synced objects when toggled on.
Files Changed
- Modified:
templates/main/auction_list.php
---
[3.2.9.1] — 2026-03-30
Timed Auction Display Enhancements
Features
- Timed Auction Countdown Text Toggle — Added a WP-Admin setting "Change text to 'Auction will close in'" that conditionally changes the countdown label for timed/online auctions on single lot pages.
- Shortcode Text Toggle Support — Extended the new countdown text logic to the
bp_upcoming_wideshortcodes so "Live bidding starts in:" successfully transitions to "Auction will close in:" for timed auctions.
Files Changed
- Modified:
inc/controllers/Settings.php,templates/single-lot.php,templates/shortcodes/upcoming-auction-wide.php,templates/shortcodes/upcoming-auction-wide-manual.php
---
[3.2.9.0] — 2026-03-29
Billing & Invoices Polish
Fixes
- Profile Invoice ID Tracking — Prevented internal auction codes (e.g.
002orai4) from breaking into the clean hyphenated titles inside theprofile-templates.phpview. - Dynamic Payment Statuses — Replaced Bidspirit's default/cached
NOT PAIDHTML payloads by wiring thedompdfgenerator to directly respect the current$b.statusstring from the API (resolving instances where a paid invoice still printed "NOT PAID" atop the document). - Payment Instructions Conditional — Automatically hide the "Payment Instructions" block from the PDF footer when an invoice is fully paid.
- Improved Nomenclature — Changed "Invoice No:" to "Bidder No:" on document output to prevent confusion with static invoice ledger IDs.
---
[3.2.6.0] — 2026-03-28
Multi-Day Auction Lot Filtering Fix
Fixes
- Day 2+ showing lots from Day 1 in multi-day auctions — The
itemIndexcolumn inbp_meta_dataisvarchar(55), but the day-range filter inBidspiritQuery::bp_query_where()was comparing it as a string. With string comparison, lot numbers like'11','101'–'145'incorrectly fell between'1001'and'1450', causing Day 1 lots to leak into Day 2 results. Fixed by usingCAST(bpMeta.itemIndex AS UNSIGNED)for numeric comparison andintval()on the PHP-side boundary values. Letter lots (e.g.14A,1025A) are handled correctly —CASTstrips the suffix, keeping them grouped with their base lot number.
Files Changed
- Modified:
inc/controllers/BidspiritQuery.php
---
[3.2.5.9] — 2026-03-27
Catalog Page Fix
Fixes
- Duplicate preview hours on catalog pages — The
displayHoursfield was rendered twice: once via thebp_after_description_auctionhook inBidspiritViews.phpand once inline in the auction template. Removed the hook-based rendering to eliminate the duplication.
Files Changed
- Modified:
inc/controllers/BidspiritViews.php,templates/main/auction.php
---
[3.2.5] — 2026-03-19
Sync Reliability & Stuck Lot Prevention
Fixes
- CATALOG_PUBLISHED webhook now triggers catalog sync — Previously only sent push notifications without syncing lots. When the earlier AUCTION_CATALOG_UPDATED fired before the catalog was ready on BidSpirit, lots were never imported. CATALOG_PUBLISHED now calls
auctionCatalogUpdated()to trigger a full catalog sync when the catalog is actually available. - 0-lot API results now fail instead of silently succeeding — When BidSpirit API returns 0 lots (catalog not yet ready), the sync job now fails with an explicit error message, allowing the next webhook to create a fresh retry job.
- Expanded CDN allowlist in pre_http_request filter — The HTTP filter during bulk post insertion now allows all
*.bidspirit.comsubdomains and BidSpirit image CDNs (fastly.net,cloudfront.net). Previously onlybidspirit.comandwww.bidspirit.comwere allowed, blocking image downloads during sync and causing worker hangs. - InsertLotsBS timeout guard — Stage 5 (InsertLotsBS processing loop) now has a 180-second timeout and logs progress every 2 batches. Prevents indefinite hangs that previously required manual force-kill.
- fixResult() no longer marks lots as done when postId=0 — When
lotProcessing()fails to create a WP post, the staging row now keepssyncFinished=0so the lot is retried on the next sync pass, instead of being permanently marked as complete with no actual post. - lotProcessing() logs error on missing auction term — Previously returned 0 silently when
Auction::findAuctionById()failed. Now logs an explicit error that feeds intofixResult()to keep the lot retryable. - Hourly orphan detection in safety cron — New step in
syncSafety.phpdetects lot posts that exist inbp_meta_databut are missing their auction taxonomy assignment (caused by workers killed mid-batch) and auto-repairs them withwp_set_object_terms().
Files Changed
- Modified:
inc/controllers/AuctionsAPI.php,inc/sync/CatalogSyncWorker.php,inc/abs/InsertLotsAbstract.php,inc/import/InsertLotsBS.php,crontasks/syncSafety.php
---
[3.2.4] — 2026-03-18
Sync Worker Hang Fix
Fixes
- Sync workers hanging at InsertLotsBS stage — Third-party plugins (Smush Pro, SmartCrawl SEO, WPMU DEV Updates) hook into
wp_insert_post()and make blocking outbound HTTPS calls for every lot processed. With 489+ lots per auction, this caused workers to hang indefinitely on socket reads to WPMU DEV servers (32.193.94.25,32.193.93.106). AddedWP_IMPORTINGconstant at the REST worker entry point and apre_http_requestfilter inCatalogSyncWorkerthat blocks all non-essential external HTTP during the batch post-insertion phase. Loopback (127.0.0.1,localhost) and BidSpirit API calls remain allowed. - Stuck staging rows after force-kill — When workers were force-killed mid-sync, staging rows in
import_historywere left withsyncstart=1and never unblocked. Subsequent sync runs could not see these rows (filtered out byLot::getRawLots()), causing the InsertLotsBS loop to exit immediately with 0 posts processed. Combined with job deduplication (SyncQueue::enqueue()skips if aprocessingjob exists), this created a deadlock where no new sync could proceed.
Files Changed
- Modified:
auctionforge.php,inc/sync/CatalogSyncWorker.php
---
[3.2.2] — 2026-03-17
Full Sync Auction Discovery Fix
Fixes
- Full Sync finds no auctions on fresh sites — The v3
full_syncaction only queried the WordPress database for existing auction terms, but on a freshly deployed site the database has zero auctions. AddedAuctionList::init()discovery step before querying the DB, so Full Sync now fetches all auctions from the BidSpirit API and creates taxonomy terms first, then enqueues catalog sync jobs for each.
Files Changed
- Modified:
auctionforge.php
---
[3.2.0] — 2026-03-14
Webhook Pipeline Fixes, Archive Sync & Admin UI Overhaul
New Features
- Archive Sync — New "Archive Sync" button on Sync Status admin page. Enqueues catalog sync jobs for all ARCHIVED/ENDED auctions. Past auctions now appear in the auction dropdown with an optgroup separator and state label.
- Sync Tasks v3 — Replaced old v2 task cards (importData, importBidSpirit, lotBidSpiritOld) with v3 queue-based tasks. "Sync Active Auctions" and "Sync Archived Auctions" now enqueue jobs via the queue system. Maintenance tasks (Clean Draft/Trash Lots, Clean Orphaned Meta) remain as direct-execution tasks.
- How It Works guide rewritten — Complete rewrite of the admin guide for v3 architecture. Documents webhook-first flow, all 5 job types, queue system mechanics, cron setup (external + WP-Cron), configuration constants, and troubleshooting.
Fixes
- Dual-write removed — Removed legacy handlers from
auctionCatalogUpdated(),auctionDayEnded(), anditemsUpdated()webhook methods. The old handlers were racing with the v3 worker, creating orphaned staging rows inimport_historythat were never processed. All three methods now exclusively use the v3 enqueue → spawn path. - ITEMS_UPDATED webhook — Fixed
itemsUpdated()failing to enqueue jobs. TheITEMS_UPDATEDpayload hasauctionIdnested initemsByLanguage.{lang}[0].item.auctionId, not at the top level. Added extraction logic to resolve it. - ItemUpdateWorker incomplete —
ItemUpdateWorker::process()was only callingLot::bulkSave()(staging table) without runningInsertLotsBSto process staged data into WP posts andbp_meta_data. Added the InsertLotsBS processing step with autocommit restore. Item updates now flow: stage → InsertLotsBS → WP post + meta → cache clear. - Worker spawn reliability — Changed
SyncQueue::spawnWorker()from non-blocking HTTPS to blocking HTTP loopback (http://127.0.0.1with explicitHostheader, 2s timeout). Fixes nginx 403/404 errors when HTTPS loopback hits the default vhost instead of the site's vhost. - API token constant — Plugin expects
AUCTIONFORGE_API_TOKENinwp-config.php(renamed fromUCO_API_TOKENduring the plugin rename). Documented in readme.
Database
- DB version: 22 → 23
Files Changed
- Modified:
inc/controllers/AuctionsAPI.php,inc/sync/ItemUpdateWorker.php,inc/sync/SyncQueue.php,auctionforge.php,admin/view/sync-status.php,readme.txt
---
[3.0.0] — 2025-03-14
New Feature: Webhook-First Sync Architecture (Sync v3)
Overview: Complete redesign of the BidSpirit data synchronisation pipeline. Replaces the old two-phase polling system (importBidSpirit every hour + importData every minute) with a webhook-driven job queue that processes data in near real-time.
Architecture
- 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: webhook → queue → background worker → WordPress posts. - Dual-write mode — During transition, webhooks enqueue jobs AND still run the legacy handlers. Once verified, legacy handlers can be removed cleanly.
- Job deduplication — Prevents duplicate work by checking for existing pending/processing jobs with the same auction_id + job_type.
New Components
- Job Queue System (
inc/sync/SyncQueue.php) — Priority-based FIFO queue with atomic job claiming, status tracking (pending/processing/completed/failed/skipped), worker PID tracking, and automatic stuck job recovery. - Sync Logger (
inc/sync/SyncLogger.php) — Real-time log table for admin console polling with level filtering (info/success/warning/error) and incremental cursor-based retrieval. - Catalog Sync Worker (
inc/sync/CatalogSyncWorker.php) — Processes catalog_sync, full_sync, and day_ended jobs by reusing existingLotList::singleRun()logic. - Item Update Worker (
inc/sync/ItemUpdateWorker.php) — Processes individual item_update jobs with the same logic as the webhookitemsUpdatedhandler. - Background Worker (
crontasks/syncWorker.php) — Async CLI process spawned by webhooks viaexec()or by the safety cron. Claims and processes queued jobs with a configurable timeout (default 240s). - Safety Net (
crontasks/syncSafety.php) — Hourly cron that resets stuck jobs (>10min), spawns workers for pending jobs, runs a 24-hour health check (auto-enqueues full sync if no webhooks received), and purges old data.
Admin UI
- Queue Status Dashboard — New card on Sync Status page showing pending/processing/completed/failed/skipped counts, recent jobs table with real-time refresh, worker status badge, and action buttons:
- Full Sync — Enqueues catalog sync for all active auctions
- Sync Selected — Enqueue a single auction from dropdown
- Spawn Worker — Manually trigger a background worker process
- Live Console — Dark-themed terminal console on the Sync Status page. Polls
af_sync_logevery 1.5s showing timestamped, color-coded log entries from webhooks, workers, queue operations, and the safety cron. Supports pause, clear, and auto-scroll.
Cron Changes
- Removed
importData(ran every minute — ~1,440 PHP executions/day) - Removed
importBidSpirit(ran hourly — ~24 PHP executions/day) - Added
syncSafety(runs hourly at :10 — 24 PHP executions/day) - Net effect: ~62 PHP executions/hour → 1 PHP execution/hour
- WP-Cron safety hook (
auctionforge_sync_safety) — Always-active hourly event, independent of external cron - setup.sh v3 — Updated task definitions, new
migratecommand for interactive v2→v3 transition
Database
- New table:
af_sync_queue— Job queue with status, priority, source, attempts, worker PID, timing columns - New table:
af_sync_log— Real-time log entries with context, level, auction_id, job_id - DB version: 20 → 22
Constants Added
| Constant | Default | Description |
|---|---|---|
|
AUCTIONFORGE_SYNC_WORKER_TIMEOUT| 240 | Worker process timeout in seconds ||
AUCTIONFORGE_SYNC_STALE_JOB| 600 | Seconds before a processing job is considered stuck ||
AUCTIONFORGE_SYNC_HEALTH_CHECK| 86400 | Seconds without webhook before triggering full sync ||
AUCTIONFORGE_SYNC_LOG_RETENTION| 7 | Days to keep log entries ||
AUCTIONFORGE_SYNC_QUEUE_RETENTION| 30 | Days to keep completed queue jobs ||
AUCTIONFORGE_CURL_TIMEOUT| 30 | BidSpirit API cURL timeout in seconds ||
AUCTIONFORGE_PHP_BINARY| /www/server/php/83/bin/php | PHP CLI binary path for spawning workers |AJAX Handlers Added
auctionforge_sync_log_poll— Incremental log polling for live consoleauctionforge_sync_queue_status— Queue counts + recent jobs for dashboardauctionforge_sync_enqueue— Admin-triggered sync actions (full_sync, sync_auction, spawn_worker)
Fixes
- cURL timeout — BidSpiritRequest now enforces a 30-second timeout (was unlimited/0), preventing hung connections from blocking the sync pipeline.
Files Changed
- Modified:
auctionforge.php,inc/coreIncludes.php,inc/controllers/AuctionsAPI.php,inc/BidSpiritRequest.php,admin/view/sync-status.php,crontasks/setup.sh - Created:
inc/sync/SyncQueue.php,inc/sync/SyncLogger.php,inc/sync/CatalogSyncWorker.php,inc/sync/ItemUpdateWorker.php,crontasks/syncWorker.php,crontasks/syncSafety.php
---
[2.7.3.0]
Fixes
- Various stability improvements and bug fixes.
[2.7.1.2]
Fixes
- Added missing
vatAndCommission()function inloadBid()— the sales tax display on single lot pages was never being rendered because the code to callloadTemplateforvat-and-commission-templatewas missing fromapp.js.
[2.7.1.1]
Fixes
- 2 decimal places now only appear in the bid modal (Your max bid, Total Price) via
showDecimalsflag. 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.
[2.7.0.9]
Fixes
- Fixed fatal error during plugin install/upgrade:
class-stats-database.phprequire failure.
[2.7.0.0]
New Features: Advanced Lot Analytics
- Conversion Tracking, Peak Viewing Times, Pre-Sale vs Live Comparison, Category Performance, Share Analytics, Search → View Funnel, Click-Through Tracking, CSV Export, Hot Lot Badge.
- New DB table:
af_lot_shares. New columns onaf_lot_analytics. DB version bumped to 20.
[2.6.0.0]
New Feature: Lot Analytics
- Comprehensive lot view and favorite tracking system with admin dashboard.
[2.5.0.0]
New Features
- Site Statistics System — Full website analytics built into the plugin admin.
- Recently Viewed Items — Profile page tab showing last 20 viewed lots per user.
-
v3.6.1.2 Stable Apr 29, 2026Download v3.6.1.2📦 8.95 MB⚙️ WP 5.2+🔧 PHP 7.2+✓ Tested 6.4
AuctionForge Changelog
All notable changes to the AuctionForge plugin are documented in this file.
---
[3.6.0.18] — 2026-04-25
Brevo SMS Notifications Integration
Features
- Transactional SMS via Brevo API — The plugin now sends text message alerts through the Brevo transactional SMS service, running alongside existing Firebase push notifications.
- Four Notification Types:
- New Auction Published — Broadcast SMS to all opted-in subscribers when an auction is published.
- Auction Starting Soon — Targeted SMS to users registered for an auction when it is about to start.
- Favorited Item Live Soon — Targeted SMS to users who favorited a lot when it is approaching in the auction.
- Outbid Notice — SMS sent when a user's leading bid is surpassed, with a 5-minute per-item cooldown to prevent spam.
- SMS Subscriber Database — New
af_sms_subscriberstable stores user phone numbers, country codes, and per-notification-type opt-in preferences (GDPR-ready explicit consent). - Admin Settings Tab — New "SMS Notifications" tab in Settings with:
- Brevo API Key input
- SMS Sender Name (11 char max)
- Master enable/disable toggle
- Per-notification-type on/off switches
- Test SMS widget with phone input and send button
- Live subscriber count display
- Profile SMS Preferences — Users can opt into SMS notifications directly from their profile page with phone number entry and granular notification type selection.
Architecture
- BrevoSMS Service (
inc/services/BrevoSMS.php) — cURL-based API wrapper with broadcast, targeted, and single-send methods, message builders with 160-char limit awareness, rate limiting, and comprehensive error logging. - SMSSubscriber Model (
inc/model/SMSSubscriber.php) — CRUD operations, email-to-phone resolution, opt-in filtering, and upsert logic. - Webhook Integration — SMS dispatch hooks added to
AuctionsAPI.phpmethods:leading_bid_surpassed(),item_live_soon(),auction_starts_soon(), andauctionPublishedPush().
AJAX Handlers
auctionforge_sms_save— Save SMS preferences from profile pageauctionforge_sms_load— Load SMS preferences for profile pageauctionforge_sms_test— Admin-only test SMS endpoint
Database
- New table:
af_sms_subscribers— Phone numbers, country codes, per-notification opt-ins, timestamps
Files Changed
- Modified:
auctionforge.php,inc/coreIncludes.php,inc/controllers/AuctionsAPI.php,inc/controllers/Settings.php,admin/view/settings.php,templates/parts/profile-templates.php - Created:
inc/services/BrevoSMS.php,inc/model/SMSSubscriber.php
---
[3.6.0.7] — 2026-04-14
Hotfix
Fixes
- Namespace resolution — Fixed fatal error in
wp_footercommission label hook caused by unqualifiedSettingsHelperandSettingsclass references. Now uses fully qualified namespaces.
Files Changed
- Modified:
auctionforge.php
---
[3.6.0.6] — 2026-04-14
Commission Label Override Fix
Fixes
- Theme template override compatibility — Moved the commission label JS override from the
single-lot.phptemplate intoauctionforge.phpviawp_footerhook (priority 99). Sites with theme-level template overrides (e.g.themes/*/auctionforge/single-lot.php) were not picking up the inline script. Thewp_footerapproach works universally on all single lot pages.
Files Changed
- Modified:
auctionforge.php,templates/single-lot.php
---
[3.6.0.5] — 2026-04-14
Commission Label Override
Features
- Commission Label Setting — New dropdown in Settings → Appearance allowing admins to choose between "Buyer's Premium" (default) and "Auction House Commission" as the label displayed on lot pages. This overrides the Bidspirit JS client's default label using a MutationObserver that catches asynchronously injected text.
Files Changed
- Modified:
inc/controllers/Settings.php,templates/single-lot.php
---
[3.6.0.4] — 2026-04-12
Auction Approval Modal Redesign
Changes
- Removed BidSpirit Terms of Use — The generic BidSpirit "Terms of Use" section that appeared at the top of the non-credit-card approval modal has been removed. The modal now shows only the auction house's own legal agreements managed within the plugin.
- Renamed Modal Title — Changed "Terms of conditions" to "Terms & Conditions".
- Larger Scroll Area — The Terms & Conditions scroll box is now 350px tall (up from 200px) for easier reading.
- Proportional Section Heights — Refund & Return Policy and Chargeback Waiver sections use a shorter 260px scroll box to visually distinguish them from the primary Terms & Conditions.
Files Changed
- Modified:
templates/js-chunks/approval-info.php,assets/js/app.js
---
[3.6.0.2] — 2026-04-10
Webhook Token Generator
Features
- Token Generator Widget — Added a 16-character random token generator directly below the "Webhook auth token" field on the Settings page. Includes a "Generate Token" button and a clipboard copy icon with visual feedback.
Files Changed
- Modified:
inc/controllers/Settings.php
---
[3.6.0.1] — 2026-04-10
Patch
Changes
- Version bump.
---
[3.6.0.0] — 2026-04-10
Legal Agreements for Auction Approval
Features
- Terms & Conditions — A mandatory, scrollable Terms & Conditions document is now displayed during the auction approval process. Bidders must scroll to the bottom and check an agreement box before their approval request is submitted. Always enabled.
- Refund & Return Policy — An optional, scrollable Refund & Return Policy can be enabled in Settings. When enabled, bidders must read and accept it during auction approval.
- Chargeback Waiver — An optional, scrollable Chargeback Waiver can be enabled in Settings. When enabled, bidders must read and accept it during auction approval.
- Admin Management — New "Legal Agreements" page under the Bidspirit admin menu with tabbed TinyMCE editors for each agreement type. Includes automatic version numbering (incremented on content change) and full version history.
- Consent Logging — Every agreement acceptance is logged to a dedicated database table (
af_user_agreement_log) with the agreement type, version, user email, IP address, user agent, auction ID, and timestamp. - User Tracking Integration — Agreement events (
terms_agreement,refund_agreement,chargeback_waiver) are also recorded in the existing IP tracking system alongside registration, login, and bid events. - Placeholder Content — Default sample content is seeded on plugin activation for all three agreement types.
Settings Added
- Enable Refund & Return Policy — Toggle to require bidders to accept the refund policy during auction approval.
- Enable Chargeback Waiver — Toggle to require bidders to accept the chargeback waiver during auction approval.
Database
- New table:
af_legal_agreements— Current active agreement content per type - New table:
af_legal_agreement_versions— Version history archive - New table:
af_user_agreement_log— User consent records
Files Changed
- Modified:
auctionforge.php,inc/controllers/Settings.php,inc/controllers/BidspiritViews.php,inc/ip-logger.php,templates/js-chunks/approval-info.php,assets/js/app.js - Created:
inc/legal/class-legal-agreements.php,admin/view/legal-agreements.php
---
[3.5.0.6] — 2026-04-08
Bid Event Tracking
Features
- Bid Tracking — All successful bids (regular, catalog, pre-sale buyout, post-sale purchase) now fire
afLogIP("bid", bidspiritUser)to capture the bidder's full identity in the user tracking table. - Whitelist Update — Added
bidto the allowedevent_typevalues in both the local plugin and the central WPDeploy API.
---
[3.5.0.5] — 2026-04-08
Self-Healing Database Schema
Features
- Auto-Migration — The plugin now auto-detects and adds any missing tracking table columns on version upgrade, ensuring sites with older schemas seamlessly migrate without manual SQL.
---
[3.5.0.4] — 2026-04-08
API Key Auto-Healing
Features
- Seamless Self-Registration — The WordPress plugin now autonomously regenerates and saves a fresh API Key whenever WPDeploy rejects a payload with an
api_key_collisionerror. This guarantees zero-downtime security handovers when developers clone instances to proxy/staging servers.
---
[3.5.0.3] — 2026-04-08
API Key Collision Defense
Features
- 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_collisionerrors, directly instructing developers to update cloned keys.
---
[3.5.0.2] — 2026-04-08
Modal Trigger Hotfix
Fixes
- Restructured internal UI rendering priority to gracefully deploy the inline Modal triggers inside custom IP log view without colliding with cached
z-indexstacks.
---
[3.5.0.1] — 2026-04-08
Hotfix
Fixes
- Timed Auction Badge Visibility — Fixed a strict type-matching bug in the main
auction_list.phpcore file that incorrectly hid the "Timed Auction" badge overlay from valid timed/online auctions on the main upcoming/archive views. The badge now displays properly across all manual and Bidspirit-synced objects when toggled on.
Files Changed
- Modified:
templates/main/auction_list.php
---
[3.2.9.1] — 2026-03-30
Timed Auction Display Enhancements
Features
- Timed Auction Countdown Text Toggle — Added a WP-Admin setting "Change text to 'Auction will close in'" that conditionally changes the countdown label for timed/online auctions on single lot pages.
- Shortcode Text Toggle Support — Extended the new countdown text logic to the
bp_upcoming_wideshortcodes so "Live bidding starts in:" successfully transitions to "Auction will close in:" for timed auctions.
Files Changed
- Modified:
inc/controllers/Settings.php,templates/single-lot.php,templates/shortcodes/upcoming-auction-wide.php,templates/shortcodes/upcoming-auction-wide-manual.php
---
[3.2.9.0] — 2026-03-29
Billing & Invoices Polish
Fixes
- Profile Invoice ID Tracking — Prevented internal auction codes (e.g.
002orai4) from breaking into the clean hyphenated titles inside theprofile-templates.phpview. - Dynamic Payment Statuses — Replaced Bidspirit's default/cached
NOT PAIDHTML payloads by wiring thedompdfgenerator to directly respect the current$b.statusstring from the API (resolving instances where a paid invoice still printed "NOT PAID" atop the document). - Payment Instructions Conditional — Automatically hide the "Payment Instructions" block from the PDF footer when an invoice is fully paid.
- Improved Nomenclature — Changed "Invoice No:" to "Bidder No:" on document output to prevent confusion with static invoice ledger IDs.
---
[3.2.6.0] — 2026-03-28
Multi-Day Auction Lot Filtering Fix
Fixes
- Day 2+ showing lots from Day 1 in multi-day auctions — The
itemIndexcolumn inbp_meta_dataisvarchar(55), but the day-range filter inBidspiritQuery::bp_query_where()was comparing it as a string. With string comparison, lot numbers like'11','101'–'145'incorrectly fell between'1001'and'1450', causing Day 1 lots to leak into Day 2 results. Fixed by usingCAST(bpMeta.itemIndex AS UNSIGNED)for numeric comparison andintval()on the PHP-side boundary values. Letter lots (e.g.14A,1025A) are handled correctly —CASTstrips the suffix, keeping them grouped with their base lot number.
Files Changed
- Modified:
inc/controllers/BidspiritQuery.php
---
[3.2.5.9] — 2026-03-27
Catalog Page Fix
Fixes
- Duplicate preview hours on catalog pages — The
displayHoursfield was rendered twice: once via thebp_after_description_auctionhook inBidspiritViews.phpand once inline in the auction template. Removed the hook-based rendering to eliminate the duplication.
Files Changed
- Modified:
inc/controllers/BidspiritViews.php,templates/main/auction.php
---
[3.2.5] — 2026-03-19
Sync Reliability & Stuck Lot Prevention
Fixes
- CATALOG_PUBLISHED webhook now triggers catalog sync — Previously only sent push notifications without syncing lots. When the earlier AUCTION_CATALOG_UPDATED fired before the catalog was ready on BidSpirit, lots were never imported. CATALOG_PUBLISHED now calls
auctionCatalogUpdated()to trigger a full catalog sync when the catalog is actually available. - 0-lot API results now fail instead of silently succeeding — When BidSpirit API returns 0 lots (catalog not yet ready), the sync job now fails with an explicit error message, allowing the next webhook to create a fresh retry job.
- Expanded CDN allowlist in pre_http_request filter — The HTTP filter during bulk post insertion now allows all
*.bidspirit.comsubdomains and BidSpirit image CDNs (fastly.net,cloudfront.net). Previously onlybidspirit.comandwww.bidspirit.comwere allowed, blocking image downloads during sync and causing worker hangs. - InsertLotsBS timeout guard — Stage 5 (InsertLotsBS processing loop) now has a 180-second timeout and logs progress every 2 batches. Prevents indefinite hangs that previously required manual force-kill.
- fixResult() no longer marks lots as done when postId=0 — When
lotProcessing()fails to create a WP post, the staging row now keepssyncFinished=0so the lot is retried on the next sync pass, instead of being permanently marked as complete with no actual post. - lotProcessing() logs error on missing auction term — Previously returned 0 silently when
Auction::findAuctionById()failed. Now logs an explicit error that feeds intofixResult()to keep the lot retryable. - Hourly orphan detection in safety cron — New step in
syncSafety.phpdetects lot posts that exist inbp_meta_databut are missing their auction taxonomy assignment (caused by workers killed mid-batch) and auto-repairs them withwp_set_object_terms().
Files Changed
- Modified:
inc/controllers/AuctionsAPI.php,inc/sync/CatalogSyncWorker.php,inc/abs/InsertLotsAbstract.php,inc/import/InsertLotsBS.php,crontasks/syncSafety.php
---
[3.2.4] — 2026-03-18
Sync Worker Hang Fix
Fixes
- Sync workers hanging at InsertLotsBS stage — Third-party plugins (Smush Pro, SmartCrawl SEO, WPMU DEV Updates) hook into
wp_insert_post()and make blocking outbound HTTPS calls for every lot processed. With 489+ lots per auction, this caused workers to hang indefinitely on socket reads to WPMU DEV servers (32.193.94.25,32.193.93.106). AddedWP_IMPORTINGconstant at the REST worker entry point and apre_http_requestfilter inCatalogSyncWorkerthat blocks all non-essential external HTTP during the batch post-insertion phase. Loopback (127.0.0.1,localhost) and BidSpirit API calls remain allowed. - Stuck staging rows after force-kill — When workers were force-killed mid-sync, staging rows in
import_historywere left withsyncstart=1and never unblocked. Subsequent sync runs could not see these rows (filtered out byLot::getRawLots()), causing the InsertLotsBS loop to exit immediately with 0 posts processed. Combined with job deduplication (SyncQueue::enqueue()skips if aprocessingjob exists), this created a deadlock where no new sync could proceed.
Files Changed
- Modified:
auctionforge.php,inc/sync/CatalogSyncWorker.php
---
[3.2.2] — 2026-03-17
Full Sync Auction Discovery Fix
Fixes
- Full Sync finds no auctions on fresh sites — The v3
full_syncaction only queried the WordPress database for existing auction terms, but on a freshly deployed site the database has zero auctions. AddedAuctionList::init()discovery step before querying the DB, so Full Sync now fetches all auctions from the BidSpirit API and creates taxonomy terms first, then enqueues catalog sync jobs for each.
Files Changed
- Modified:
auctionforge.php
---
[3.2.0] — 2026-03-14
Webhook Pipeline Fixes, Archive Sync & Admin UI Overhaul
New Features
- Archive Sync — New "Archive Sync" button on Sync Status admin page. Enqueues catalog sync jobs for all ARCHIVED/ENDED auctions. Past auctions now appear in the auction dropdown with an optgroup separator and state label.
- Sync Tasks v3 — Replaced old v2 task cards (importData, importBidSpirit, lotBidSpiritOld) with v3 queue-based tasks. "Sync Active Auctions" and "Sync Archived Auctions" now enqueue jobs via the queue system. Maintenance tasks (Clean Draft/Trash Lots, Clean Orphaned Meta) remain as direct-execution tasks.
- How It Works guide rewritten — Complete rewrite of the admin guide for v3 architecture. Documents webhook-first flow, all 5 job types, queue system mechanics, cron setup (external + WP-Cron), configuration constants, and troubleshooting.
Fixes
- Dual-write removed — Removed legacy handlers from
auctionCatalogUpdated(),auctionDayEnded(), anditemsUpdated()webhook methods. The old handlers were racing with the v3 worker, creating orphaned staging rows inimport_historythat were never processed. All three methods now exclusively use the v3 enqueue → spawn path. - ITEMS_UPDATED webhook — Fixed
itemsUpdated()failing to enqueue jobs. TheITEMS_UPDATEDpayload hasauctionIdnested initemsByLanguage.{lang}[0].item.auctionId, not at the top level. Added extraction logic to resolve it. - ItemUpdateWorker incomplete —
ItemUpdateWorker::process()was only callingLot::bulkSave()(staging table) without runningInsertLotsBSto process staged data into WP posts andbp_meta_data. Added the InsertLotsBS processing step with autocommit restore. Item updates now flow: stage → InsertLotsBS → WP post + meta → cache clear. - Worker spawn reliability — Changed
SyncQueue::spawnWorker()from non-blocking HTTPS to blocking HTTP loopback (http://127.0.0.1with explicitHostheader, 2s timeout). Fixes nginx 403/404 errors when HTTPS loopback hits the default vhost instead of the site's vhost. - API token constant — Plugin expects
AUCTIONFORGE_API_TOKENinwp-config.php(renamed fromUCO_API_TOKENduring the plugin rename). Documented in readme.
Database
- DB version: 22 → 23
Files Changed
- Modified:
inc/controllers/AuctionsAPI.php,inc/sync/ItemUpdateWorker.php,inc/sync/SyncQueue.php,auctionforge.php,admin/view/sync-status.php,readme.txt
---
[3.0.0] — 2025-03-14
New Feature: Webhook-First Sync Architecture (Sync v3)
Overview: Complete redesign of the BidSpirit data synchronisation pipeline. Replaces the old two-phase polling system (importBidSpirit every hour + importData every minute) with a webhook-driven job queue that processes data in near real-time.
Architecture
- 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: webhook → queue → background worker → WordPress posts. - Dual-write mode — During transition, webhooks enqueue jobs AND still run the legacy handlers. Once verified, legacy handlers can be removed cleanly.
- Job deduplication — Prevents duplicate work by checking for existing pending/processing jobs with the same auction_id + job_type.
New Components
- Job Queue System (
inc/sync/SyncQueue.php) — Priority-based FIFO queue with atomic job claiming, status tracking (pending/processing/completed/failed/skipped), worker PID tracking, and automatic stuck job recovery. - Sync Logger (
inc/sync/SyncLogger.php) — Real-time log table for admin console polling with level filtering (info/success/warning/error) and incremental cursor-based retrieval. - Catalog Sync Worker (
inc/sync/CatalogSyncWorker.php) — Processes catalog_sync, full_sync, and day_ended jobs by reusing existingLotList::singleRun()logic. - Item Update Worker (
inc/sync/ItemUpdateWorker.php) — Processes individual item_update jobs with the same logic as the webhookitemsUpdatedhandler. - Background Worker (
crontasks/syncWorker.php) — Async CLI process spawned by webhooks viaexec()or by the safety cron. Claims and processes queued jobs with a configurable timeout (default 240s). - Safety Net (
crontasks/syncSafety.php) — Hourly cron that resets stuck jobs (>10min), spawns workers for pending jobs, runs a 24-hour health check (auto-enqueues full sync if no webhooks received), and purges old data.
Admin UI
- Queue Status Dashboard — New card on Sync Status page showing pending/processing/completed/failed/skipped counts, recent jobs table with real-time refresh, worker status badge, and action buttons:
- Full Sync — Enqueues catalog sync for all active auctions
- Sync Selected — Enqueue a single auction from dropdown
- Spawn Worker — Manually trigger a background worker process
- Live Console — Dark-themed terminal console on the Sync Status page. Polls
af_sync_logevery 1.5s showing timestamped, color-coded log entries from webhooks, workers, queue operations, and the safety cron. Supports pause, clear, and auto-scroll.
Cron Changes
- Removed
importData(ran every minute — ~1,440 PHP executions/day) - Removed
importBidSpirit(ran hourly — ~24 PHP executions/day) - Added
syncSafety(runs hourly at :10 — 24 PHP executions/day) - Net effect: ~62 PHP executions/hour → 1 PHP execution/hour
- WP-Cron safety hook (
auctionforge_sync_safety) — Always-active hourly event, independent of external cron - setup.sh v3 — Updated task definitions, new
migratecommand for interactive v2→v3 transition
Database
- New table:
af_sync_queue— Job queue with status, priority, source, attempts, worker PID, timing columns - New table:
af_sync_log— Real-time log entries with context, level, auction_id, job_id - DB version: 20 → 22
Constants Added
| Constant | Default | Description |
|---|---|---|
|
AUCTIONFORGE_SYNC_WORKER_TIMEOUT| 240 | Worker process timeout in seconds ||
AUCTIONFORGE_SYNC_STALE_JOB| 600 | Seconds before a processing job is considered stuck ||
AUCTIONFORGE_SYNC_HEALTH_CHECK| 86400 | Seconds without webhook before triggering full sync ||
AUCTIONFORGE_SYNC_LOG_RETENTION| 7 | Days to keep log entries ||
AUCTIONFORGE_SYNC_QUEUE_RETENTION| 30 | Days to keep completed queue jobs ||
AUCTIONFORGE_CURL_TIMEOUT| 30 | BidSpirit API cURL timeout in seconds ||
AUCTIONFORGE_PHP_BINARY| /www/server/php/83/bin/php | PHP CLI binary path for spawning workers |AJAX Handlers Added
auctionforge_sync_log_poll— Incremental log polling for live consoleauctionforge_sync_queue_status— Queue counts + recent jobs for dashboardauctionforge_sync_enqueue— Admin-triggered sync actions (full_sync, sync_auction, spawn_worker)
Fixes
- cURL timeout — BidSpiritRequest now enforces a 30-second timeout (was unlimited/0), preventing hung connections from blocking the sync pipeline.
Files Changed
- Modified:
auctionforge.php,inc/coreIncludes.php,inc/controllers/AuctionsAPI.php,inc/BidSpiritRequest.php,admin/view/sync-status.php,crontasks/setup.sh - Created:
inc/sync/SyncQueue.php,inc/sync/SyncLogger.php,inc/sync/CatalogSyncWorker.php,inc/sync/ItemUpdateWorker.php,crontasks/syncWorker.php,crontasks/syncSafety.php
---
[2.7.3.0]
Fixes
- Various stability improvements and bug fixes.
[2.7.1.2]
Fixes
- Added missing
vatAndCommission()function inloadBid()— the sales tax display on single lot pages was never being rendered because the code to callloadTemplateforvat-and-commission-templatewas missing fromapp.js.
[2.7.1.1]
Fixes
- 2 decimal places now only appear in the bid modal (Your max bid, Total Price) via
showDecimalsflag. 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.
[2.7.0.9]
Fixes
- Fixed fatal error during plugin install/upgrade:
class-stats-database.phprequire failure.
[2.7.0.0]
New Features: Advanced Lot Analytics
- Conversion Tracking, Peak Viewing Times, Pre-Sale vs Live Comparison, Category Performance, Share Analytics, Search → View Funnel, Click-Through Tracking, CSV Export, Hot Lot Badge.
- New DB table:
af_lot_shares. New columns onaf_lot_analytics. DB version bumped to 20.
[2.6.0.0]
New Feature: Lot Analytics
- Comprehensive lot view and favorite tracking system with admin dashboard.
[2.5.0.0]
New Features
- Site Statistics System — Full website analytics built into the plugin admin.
- Recently Viewed Items — Profile page tab showing last 20 viewed lots per user.
-
v3.6.1.1 Stable Apr 27, 2026Download v3.6.1.1📦 8.95 MB⚙️ WP 5.2+🔧 PHP 7.2+✓ Tested 6.4
AuctionForge Changelog
All notable changes to the AuctionForge plugin are documented in this file.
---
[3.6.0.18] — 2026-04-25
Brevo SMS Notifications Integration
Features
- Transactional SMS via Brevo API — The plugin now sends text message alerts through the Brevo transactional SMS service, running alongside existing Firebase push notifications.
- Four Notification Types:
- New Auction Published — Broadcast SMS to all opted-in subscribers when an auction is published.
- Auction Starting Soon — Targeted SMS to users registered for an auction when it is about to start.
- Favorited Item Live Soon — Targeted SMS to users who favorited a lot when it is approaching in the auction.
- Outbid Notice — SMS sent when a user's leading bid is surpassed, with a 5-minute per-item cooldown to prevent spam.
- SMS Subscriber Database — New
af_sms_subscriberstable stores user phone numbers, country codes, and per-notification-type opt-in preferences (GDPR-ready explicit consent). - Admin Settings Tab — New "SMS Notifications" tab in Settings with:
- Brevo API Key input
- SMS Sender Name (11 char max)
- Master enable/disable toggle
- Per-notification-type on/off switches
- Test SMS widget with phone input and send button
- Live subscriber count display
- Profile SMS Preferences — Users can opt into SMS notifications directly from their profile page with phone number entry and granular notification type selection.
Architecture
- BrevoSMS Service (
inc/services/BrevoSMS.php) — cURL-based API wrapper with broadcast, targeted, and single-send methods, message builders with 160-char limit awareness, rate limiting, and comprehensive error logging. - SMSSubscriber Model (
inc/model/SMSSubscriber.php) — CRUD operations, email-to-phone resolution, opt-in filtering, and upsert logic. - Webhook Integration — SMS dispatch hooks added to
AuctionsAPI.phpmethods:leading_bid_surpassed(),item_live_soon(),auction_starts_soon(), andauctionPublishedPush().
AJAX Handlers
auctionforge_sms_save— Save SMS preferences from profile pageauctionforge_sms_load— Load SMS preferences for profile pageauctionforge_sms_test— Admin-only test SMS endpoint
Database
- New table:
af_sms_subscribers— Phone numbers, country codes, per-notification opt-ins, timestamps
Files Changed
- Modified:
auctionforge.php,inc/coreIncludes.php,inc/controllers/AuctionsAPI.php,inc/controllers/Settings.php,admin/view/settings.php,templates/parts/profile-templates.php - Created:
inc/services/BrevoSMS.php,inc/model/SMSSubscriber.php
---
[3.6.0.7] — 2026-04-14
Hotfix
Fixes
- Namespace resolution — Fixed fatal error in
wp_footercommission label hook caused by unqualifiedSettingsHelperandSettingsclass references. Now uses fully qualified namespaces.
Files Changed
- Modified:
auctionforge.php
---
[3.6.0.6] — 2026-04-14
Commission Label Override Fix
Fixes
- Theme template override compatibility — Moved the commission label JS override from the
single-lot.phptemplate intoauctionforge.phpviawp_footerhook (priority 99). Sites with theme-level template overrides (e.g.themes/*/auctionforge/single-lot.php) were not picking up the inline script. Thewp_footerapproach works universally on all single lot pages.
Files Changed
- Modified:
auctionforge.php,templates/single-lot.php
---
[3.6.0.5] — 2026-04-14
Commission Label Override
Features
- Commission Label Setting — New dropdown in Settings → Appearance allowing admins to choose between "Buyer's Premium" (default) and "Auction House Commission" as the label displayed on lot pages. This overrides the Bidspirit JS client's default label using a MutationObserver that catches asynchronously injected text.
Files Changed
- Modified:
inc/controllers/Settings.php,templates/single-lot.php
---
[3.6.0.4] — 2026-04-12
Auction Approval Modal Redesign
Changes
- Removed BidSpirit Terms of Use — The generic BidSpirit "Terms of Use" section that appeared at the top of the non-credit-card approval modal has been removed. The modal now shows only the auction house's own legal agreements managed within the plugin.
- Renamed Modal Title — Changed "Terms of conditions" to "Terms & Conditions".
- Larger Scroll Area — The Terms & Conditions scroll box is now 350px tall (up from 200px) for easier reading.
- Proportional Section Heights — Refund & Return Policy and Chargeback Waiver sections use a shorter 260px scroll box to visually distinguish them from the primary Terms & Conditions.
Files Changed
- Modified:
templates/js-chunks/approval-info.php,assets/js/app.js
---
[3.6.0.2] — 2026-04-10
Webhook Token Generator
Features
- Token Generator Widget — Added a 16-character random token generator directly below the "Webhook auth token" field on the Settings page. Includes a "Generate Token" button and a clipboard copy icon with visual feedback.
Files Changed
- Modified:
inc/controllers/Settings.php
---
[3.6.0.1] — 2026-04-10
Patch
Changes
- Version bump.
---
[3.6.0.0] — 2026-04-10
Legal Agreements for Auction Approval
Features
- Terms & Conditions — A mandatory, scrollable Terms & Conditions document is now displayed during the auction approval process. Bidders must scroll to the bottom and check an agreement box before their approval request is submitted. Always enabled.
- Refund & Return Policy — An optional, scrollable Refund & Return Policy can be enabled in Settings. When enabled, bidders must read and accept it during auction approval.
- Chargeback Waiver — An optional, scrollable Chargeback Waiver can be enabled in Settings. When enabled, bidders must read and accept it during auction approval.
- Admin Management — New "Legal Agreements" page under the Bidspirit admin menu with tabbed TinyMCE editors for each agreement type. Includes automatic version numbering (incremented on content change) and full version history.
- Consent Logging — Every agreement acceptance is logged to a dedicated database table (
af_user_agreement_log) with the agreement type, version, user email, IP address, user agent, auction ID, and timestamp. - User Tracking Integration — Agreement events (
terms_agreement,refund_agreement,chargeback_waiver) are also recorded in the existing IP tracking system alongside registration, login, and bid events. - Placeholder Content — Default sample content is seeded on plugin activation for all three agreement types.
Settings Added
- Enable Refund & Return Policy — Toggle to require bidders to accept the refund policy during auction approval.
- Enable Chargeback Waiver — Toggle to require bidders to accept the chargeback waiver during auction approval.
Database
- New table:
af_legal_agreements— Current active agreement content per type - New table:
af_legal_agreement_versions— Version history archive - New table:
af_user_agreement_log— User consent records
Files Changed
- Modified:
auctionforge.php,inc/controllers/Settings.php,inc/controllers/BidspiritViews.php,inc/ip-logger.php,templates/js-chunks/approval-info.php,assets/js/app.js - Created:
inc/legal/class-legal-agreements.php,admin/view/legal-agreements.php
---
[3.5.0.6] — 2026-04-08
Bid Event Tracking
Features
- Bid Tracking — All successful bids (regular, catalog, pre-sale buyout, post-sale purchase) now fire
afLogIP("bid", bidspiritUser)to capture the bidder's full identity in the user tracking table. - Whitelist Update — Added
bidto the allowedevent_typevalues in both the local plugin and the central WPDeploy API.
---
[3.5.0.5] — 2026-04-08
Self-Healing Database Schema
Features
- Auto-Migration — The plugin now auto-detects and adds any missing tracking table columns on version upgrade, ensuring sites with older schemas seamlessly migrate without manual SQL.
---
[3.5.0.4] — 2026-04-08
API Key Auto-Healing
Features
- Seamless Self-Registration — The WordPress plugin now autonomously regenerates and saves a fresh API Key whenever WPDeploy rejects a payload with an
api_key_collisionerror. This guarantees zero-downtime security handovers when developers clone instances to proxy/staging servers.
---
[3.5.0.3] — 2026-04-08
API Key Collision Defense
Features
- 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_collisionerrors, directly instructing developers to update cloned keys.
---
[3.5.0.2] — 2026-04-08
Modal Trigger Hotfix
Fixes
- Restructured internal UI rendering priority to gracefully deploy the inline Modal triggers inside custom IP log view without colliding with cached
z-indexstacks.
---
[3.5.0.1] — 2026-04-08
Hotfix
Fixes
- Timed Auction Badge Visibility — Fixed a strict type-matching bug in the main
auction_list.phpcore file that incorrectly hid the "Timed Auction" badge overlay from valid timed/online auctions on the main upcoming/archive views. The badge now displays properly across all manual and Bidspirit-synced objects when toggled on.
Files Changed
- Modified:
templates/main/auction_list.php
---
[3.2.9.1] — 2026-03-30
Timed Auction Display Enhancements
Features
- Timed Auction Countdown Text Toggle — Added a WP-Admin setting "Change text to 'Auction will close in'" that conditionally changes the countdown label for timed/online auctions on single lot pages.
- Shortcode Text Toggle Support — Extended the new countdown text logic to the
bp_upcoming_wideshortcodes so "Live bidding starts in:" successfully transitions to "Auction will close in:" for timed auctions.
Files Changed
- Modified:
inc/controllers/Settings.php,templates/single-lot.php,templates/shortcodes/upcoming-auction-wide.php,templates/shortcodes/upcoming-auction-wide-manual.php
---
[3.2.9.0] — 2026-03-29
Billing & Invoices Polish
Fixes
- Profile Invoice ID Tracking — Prevented internal auction codes (e.g.
002orai4) from breaking into the clean hyphenated titles inside theprofile-templates.phpview. - Dynamic Payment Statuses — Replaced Bidspirit's default/cached
NOT PAIDHTML payloads by wiring thedompdfgenerator to directly respect the current$b.statusstring from the API (resolving instances where a paid invoice still printed "NOT PAID" atop the document). - Payment Instructions Conditional — Automatically hide the "Payment Instructions" block from the PDF footer when an invoice is fully paid.
- Improved Nomenclature — Changed "Invoice No:" to "Bidder No:" on document output to prevent confusion with static invoice ledger IDs.
---
[3.2.6.0] — 2026-03-28
Multi-Day Auction Lot Filtering Fix
Fixes
- Day 2+ showing lots from Day 1 in multi-day auctions — The
itemIndexcolumn inbp_meta_dataisvarchar(55), but the day-range filter inBidspiritQuery::bp_query_where()was comparing it as a string. With string comparison, lot numbers like'11','101'–'145'incorrectly fell between'1001'and'1450', causing Day 1 lots to leak into Day 2 results. Fixed by usingCAST(bpMeta.itemIndex AS UNSIGNED)for numeric comparison andintval()on the PHP-side boundary values. Letter lots (e.g.14A,1025A) are handled correctly —CASTstrips the suffix, keeping them grouped with their base lot number.
Files Changed
- Modified:
inc/controllers/BidspiritQuery.php
---
[3.2.5.9] — 2026-03-27
Catalog Page Fix
Fixes
- Duplicate preview hours on catalog pages — The
displayHoursfield was rendered twice: once via thebp_after_description_auctionhook inBidspiritViews.phpand once inline in the auction template. Removed the hook-based rendering to eliminate the duplication.
Files Changed
- Modified:
inc/controllers/BidspiritViews.php,templates/main/auction.php
---
[3.2.5] — 2026-03-19
Sync Reliability & Stuck Lot Prevention
Fixes
- CATALOG_PUBLISHED webhook now triggers catalog sync — Previously only sent push notifications without syncing lots. When the earlier AUCTION_CATALOG_UPDATED fired before the catalog was ready on BidSpirit, lots were never imported. CATALOG_PUBLISHED now calls
auctionCatalogUpdated()to trigger a full catalog sync when the catalog is actually available. - 0-lot API results now fail instead of silently succeeding — When BidSpirit API returns 0 lots (catalog not yet ready), the sync job now fails with an explicit error message, allowing the next webhook to create a fresh retry job.
- Expanded CDN allowlist in pre_http_request filter — The HTTP filter during bulk post insertion now allows all
*.bidspirit.comsubdomains and BidSpirit image CDNs (fastly.net,cloudfront.net). Previously onlybidspirit.comandwww.bidspirit.comwere allowed, blocking image downloads during sync and causing worker hangs. - InsertLotsBS timeout guard — Stage 5 (InsertLotsBS processing loop) now has a 180-second timeout and logs progress every 2 batches. Prevents indefinite hangs that previously required manual force-kill.
- fixResult() no longer marks lots as done when postId=0 — When
lotProcessing()fails to create a WP post, the staging row now keepssyncFinished=0so the lot is retried on the next sync pass, instead of being permanently marked as complete with no actual post. - lotProcessing() logs error on missing auction term — Previously returned 0 silently when
Auction::findAuctionById()failed. Now logs an explicit error that feeds intofixResult()to keep the lot retryable. - Hourly orphan detection in safety cron — New step in
syncSafety.phpdetects lot posts that exist inbp_meta_databut are missing their auction taxonomy assignment (caused by workers killed mid-batch) and auto-repairs them withwp_set_object_terms().
Files Changed
- Modified:
inc/controllers/AuctionsAPI.php,inc/sync/CatalogSyncWorker.php,inc/abs/InsertLotsAbstract.php,inc/import/InsertLotsBS.php,crontasks/syncSafety.php
---
[3.2.4] — 2026-03-18
Sync Worker Hang Fix
Fixes
- Sync workers hanging at InsertLotsBS stage — Third-party plugins (Smush Pro, SmartCrawl SEO, WPMU DEV Updates) hook into
wp_insert_post()and make blocking outbound HTTPS calls for every lot processed. With 489+ lots per auction, this caused workers to hang indefinitely on socket reads to WPMU DEV servers (32.193.94.25,32.193.93.106). AddedWP_IMPORTINGconstant at the REST worker entry point and apre_http_requestfilter inCatalogSyncWorkerthat blocks all non-essential external HTTP during the batch post-insertion phase. Loopback (127.0.0.1,localhost) and BidSpirit API calls remain allowed. - Stuck staging rows after force-kill — When workers were force-killed mid-sync, staging rows in
import_historywere left withsyncstart=1and never unblocked. Subsequent sync runs could not see these rows (filtered out byLot::getRawLots()), causing the InsertLotsBS loop to exit immediately with 0 posts processed. Combined with job deduplication (SyncQueue::enqueue()skips if aprocessingjob exists), this created a deadlock where no new sync could proceed.
Files Changed
- Modified:
auctionforge.php,inc/sync/CatalogSyncWorker.php
---
[3.2.2] — 2026-03-17
Full Sync Auction Discovery Fix
Fixes
- Full Sync finds no auctions on fresh sites — The v3
full_syncaction only queried the WordPress database for existing auction terms, but on a freshly deployed site the database has zero auctions. AddedAuctionList::init()discovery step before querying the DB, so Full Sync now fetches all auctions from the BidSpirit API and creates taxonomy terms first, then enqueues catalog sync jobs for each.
Files Changed
- Modified:
auctionforge.php
---
[3.2.0] — 2026-03-14
Webhook Pipeline Fixes, Archive Sync & Admin UI Overhaul
New Features
- Archive Sync — New "Archive Sync" button on Sync Status admin page. Enqueues catalog sync jobs for all ARCHIVED/ENDED auctions. Past auctions now appear in the auction dropdown with an optgroup separator and state label.
- Sync Tasks v3 — Replaced old v2 task cards (importData, importBidSpirit, lotBidSpiritOld) with v3 queue-based tasks. "Sync Active Auctions" and "Sync Archived Auctions" now enqueue jobs via the queue system. Maintenance tasks (Clean Draft/Trash Lots, Clean Orphaned Meta) remain as direct-execution tasks.
- How It Works guide rewritten — Complete rewrite of the admin guide for v3 architecture. Documents webhook-first flow, all 5 job types, queue system mechanics, cron setup (external + WP-Cron), configuration constants, and troubleshooting.
Fixes
- Dual-write removed — Removed legacy handlers from
auctionCatalogUpdated(),auctionDayEnded(), anditemsUpdated()webhook methods. The old handlers were racing with the v3 worker, creating orphaned staging rows inimport_historythat were never processed. All three methods now exclusively use the v3 enqueue → spawn path. - ITEMS_UPDATED webhook — Fixed
itemsUpdated()failing to enqueue jobs. TheITEMS_UPDATEDpayload hasauctionIdnested initemsByLanguage.{lang}[0].item.auctionId, not at the top level. Added extraction logic to resolve it. - ItemUpdateWorker incomplete —
ItemUpdateWorker::process()was only callingLot::bulkSave()(staging table) without runningInsertLotsBSto process staged data into WP posts andbp_meta_data. Added the InsertLotsBS processing step with autocommit restore. Item updates now flow: stage → InsertLotsBS → WP post + meta → cache clear. - Worker spawn reliability — Changed
SyncQueue::spawnWorker()from non-blocking HTTPS to blocking HTTP loopback (http://127.0.0.1with explicitHostheader, 2s timeout). Fixes nginx 403/404 errors when HTTPS loopback hits the default vhost instead of the site's vhost. - API token constant — Plugin expects
AUCTIONFORGE_API_TOKENinwp-config.php(renamed fromUCO_API_TOKENduring the plugin rename). Documented in readme.
Database
- DB version: 22 → 23
Files Changed
- Modified:
inc/controllers/AuctionsAPI.php,inc/sync/ItemUpdateWorker.php,inc/sync/SyncQueue.php,auctionforge.php,admin/view/sync-status.php,readme.txt
---
[3.0.0] — 2025-03-14
New Feature: Webhook-First Sync Architecture (Sync v3)
Overview: Complete redesign of the BidSpirit data synchronisation pipeline. Replaces the old two-phase polling system (importBidSpirit every hour + importData every minute) with a webhook-driven job queue that processes data in near real-time.
Architecture
- 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: webhook → queue → background worker → WordPress posts. - Dual-write mode — During transition, webhooks enqueue jobs AND still run the legacy handlers. Once verified, legacy handlers can be removed cleanly.
- Job deduplication — Prevents duplicate work by checking for existing pending/processing jobs with the same auction_id + job_type.
New Components
- Job Queue System (
inc/sync/SyncQueue.php) — Priority-based FIFO queue with atomic job claiming, status tracking (pending/processing/completed/failed/skipped), worker PID tracking, and automatic stuck job recovery. - Sync Logger (
inc/sync/SyncLogger.php) — Real-time log table for admin console polling with level filtering (info/success/warning/error) and incremental cursor-based retrieval. - Catalog Sync Worker (
inc/sync/CatalogSyncWorker.php) — Processes catalog_sync, full_sync, and day_ended jobs by reusing existingLotList::singleRun()logic. - Item Update Worker (
inc/sync/ItemUpdateWorker.php) — Processes individual item_update jobs with the same logic as the webhookitemsUpdatedhandler. - Background Worker (
crontasks/syncWorker.php) — Async CLI process spawned by webhooks viaexec()or by the safety cron. Claims and processes queued jobs with a configurable timeout (default 240s). - Safety Net (
crontasks/syncSafety.php) — Hourly cron that resets stuck jobs (>10min), spawns workers for pending jobs, runs a 24-hour health check (auto-enqueues full sync if no webhooks received), and purges old data.
Admin UI
- Queue Status Dashboard — New card on Sync Status page showing pending/processing/completed/failed/skipped counts, recent jobs table with real-time refresh, worker status badge, and action buttons:
- Full Sync — Enqueues catalog sync for all active auctions
- Sync Selected — Enqueue a single auction from dropdown
- Spawn Worker — Manually trigger a background worker process
- Live Console — Dark-themed terminal console on the Sync Status page. Polls
af_sync_logevery 1.5s showing timestamped, color-coded log entries from webhooks, workers, queue operations, and the safety cron. Supports pause, clear, and auto-scroll.
Cron Changes
- Removed
importData(ran every minute — ~1,440 PHP executions/day) - Removed
importBidSpirit(ran hourly — ~24 PHP executions/day) - Added
syncSafety(runs hourly at :10 — 24 PHP executions/day) - Net effect: ~62 PHP executions/hour → 1 PHP execution/hour
- WP-Cron safety hook (
auctionforge_sync_safety) — Always-active hourly event, independent of external cron - setup.sh v3 — Updated task definitions, new
migratecommand for interactive v2→v3 transition
Database
- New table:
af_sync_queue— Job queue with status, priority, source, attempts, worker PID, timing columns - New table:
af_sync_log— Real-time log entries with context, level, auction_id, job_id - DB version: 20 → 22
Constants Added
| Constant | Default | Description |
|---|---|---|
|
AUCTIONFORGE_SYNC_WORKER_TIMEOUT| 240 | Worker process timeout in seconds ||
AUCTIONFORGE_SYNC_STALE_JOB| 600 | Seconds before a processing job is considered stuck ||
AUCTIONFORGE_SYNC_HEALTH_CHECK| 86400 | Seconds without webhook before triggering full sync ||
AUCTIONFORGE_SYNC_LOG_RETENTION| 7 | Days to keep log entries ||
AUCTIONFORGE_SYNC_QUEUE_RETENTION| 30 | Days to keep completed queue jobs ||
AUCTIONFORGE_CURL_TIMEOUT| 30 | BidSpirit API cURL timeout in seconds ||
AUCTIONFORGE_PHP_BINARY| /www/server/php/83/bin/php | PHP CLI binary path for spawning workers |AJAX Handlers Added
auctionforge_sync_log_poll— Incremental log polling for live consoleauctionforge_sync_queue_status— Queue counts + recent jobs for dashboardauctionforge_sync_enqueue— Admin-triggered sync actions (full_sync, sync_auction, spawn_worker)
Fixes
- cURL timeout — BidSpiritRequest now enforces a 30-second timeout (was unlimited/0), preventing hung connections from blocking the sync pipeline.
Files Changed
- Modified:
auctionforge.php,inc/coreIncludes.php,inc/controllers/AuctionsAPI.php,inc/BidSpiritRequest.php,admin/view/sync-status.php,crontasks/setup.sh - Created:
inc/sync/SyncQueue.php,inc/sync/SyncLogger.php,inc/sync/CatalogSyncWorker.php,inc/sync/ItemUpdateWorker.php,crontasks/syncWorker.php,crontasks/syncSafety.php
---
[2.7.3.0]
Fixes
- Various stability improvements and bug fixes.
[2.7.1.2]
Fixes
- Added missing
vatAndCommission()function inloadBid()— the sales tax display on single lot pages was never being rendered because the code to callloadTemplateforvat-and-commission-templatewas missing fromapp.js.
[2.7.1.1]
Fixes
- 2 decimal places now only appear in the bid modal (Your max bid, Total Price) via
showDecimalsflag. 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.
[2.7.0.9]
Fixes
- Fixed fatal error during plugin install/upgrade:
class-stats-database.phprequire failure.
[2.7.0.0]
New Features: Advanced Lot Analytics
- Conversion Tracking, Peak Viewing Times, Pre-Sale vs Live Comparison, Category Performance, Share Analytics, Search → View Funnel, Click-Through Tracking, CSV Export, Hot Lot Badge.
- New DB table:
af_lot_shares. New columns onaf_lot_analytics. DB version bumped to 20.
[2.6.0.0]
New Feature: Lot Analytics
- Comprehensive lot view and favorite tracking system with admin dashboard.
[2.5.0.0]
New Features
- Site Statistics System — Full website analytics built into the plugin admin.
- Recently Viewed Items — Profile page tab showing last 20 viewed lots per user.
-
v3.6.1.0 Stable Apr 27, 2026Download v3.6.1.0📦 8.95 MB⚙️ WP 5.2+🔧 PHP 7.2+✓ Tested 6.4
AuctionForge Changelog
All notable changes to the AuctionForge plugin are documented in this file.
---
[3.6.0.18] — 2026-04-25
Brevo SMS Notifications Integration
Features
- Transactional SMS via Brevo API — The plugin now sends text message alerts through the Brevo transactional SMS service, running alongside existing Firebase push notifications.
- Four Notification Types:
- New Auction Published — Broadcast SMS to all opted-in subscribers when an auction is published.
- Auction Starting Soon — Targeted SMS to users registered for an auction when it is about to start.
- Favorited Item Live Soon — Targeted SMS to users who favorited a lot when it is approaching in the auction.
- Outbid Notice — SMS sent when a user's leading bid is surpassed, with a 5-minute per-item cooldown to prevent spam.
- SMS Subscriber Database — New
af_sms_subscriberstable stores user phone numbers, country codes, and per-notification-type opt-in preferences (GDPR-ready explicit consent). - Admin Settings Tab — New "SMS Notifications" tab in Settings with:
- Brevo API Key input
- SMS Sender Name (11 char max)
- Master enable/disable toggle
- Per-notification-type on/off switches
- Test SMS widget with phone input and send button
- Live subscriber count display
- Profile SMS Preferences — Users can opt into SMS notifications directly from their profile page with phone number entry and granular notification type selection.
Architecture
- BrevoSMS Service (
inc/services/BrevoSMS.php) — cURL-based API wrapper with broadcast, targeted, and single-send methods, message builders with 160-char limit awareness, rate limiting, and comprehensive error logging. - SMSSubscriber Model (
inc/model/SMSSubscriber.php) — CRUD operations, email-to-phone resolution, opt-in filtering, and upsert logic. - Webhook Integration — SMS dispatch hooks added to
AuctionsAPI.phpmethods:leading_bid_surpassed(),item_live_soon(),auction_starts_soon(), andauctionPublishedPush().
AJAX Handlers
auctionforge_sms_save— Save SMS preferences from profile pageauctionforge_sms_load— Load SMS preferences for profile pageauctionforge_sms_test— Admin-only test SMS endpoint
Database
- New table:
af_sms_subscribers— Phone numbers, country codes, per-notification opt-ins, timestamps
Files Changed
- Modified:
auctionforge.php,inc/coreIncludes.php,inc/controllers/AuctionsAPI.php,inc/controllers/Settings.php,admin/view/settings.php,templates/parts/profile-templates.php - Created:
inc/services/BrevoSMS.php,inc/model/SMSSubscriber.php
---
[3.6.0.7] — 2026-04-14
Hotfix
Fixes
- Namespace resolution — Fixed fatal error in
wp_footercommission label hook caused by unqualifiedSettingsHelperandSettingsclass references. Now uses fully qualified namespaces.
Files Changed
- Modified:
auctionforge.php
---
[3.6.0.6] — 2026-04-14
Commission Label Override Fix
Fixes
- Theme template override compatibility — Moved the commission label JS override from the
single-lot.phptemplate intoauctionforge.phpviawp_footerhook (priority 99). Sites with theme-level template overrides (e.g.themes/*/auctionforge/single-lot.php) were not picking up the inline script. Thewp_footerapproach works universally on all single lot pages.
Files Changed
- Modified:
auctionforge.php,templates/single-lot.php
---
[3.6.0.5] — 2026-04-14
Commission Label Override
Features
- Commission Label Setting — New dropdown in Settings → Appearance allowing admins to choose between "Buyer's Premium" (default) and "Auction House Commission" as the label displayed on lot pages. This overrides the Bidspirit JS client's default label using a MutationObserver that catches asynchronously injected text.
Files Changed
- Modified:
inc/controllers/Settings.php,templates/single-lot.php
---
[3.6.0.4] — 2026-04-12
Auction Approval Modal Redesign
Changes
- Removed BidSpirit Terms of Use — The generic BidSpirit "Terms of Use" section that appeared at the top of the non-credit-card approval modal has been removed. The modal now shows only the auction house's own legal agreements managed within the plugin.
- Renamed Modal Title — Changed "Terms of conditions" to "Terms & Conditions".
- Larger Scroll Area — The Terms & Conditions scroll box is now 350px tall (up from 200px) for easier reading.
- Proportional Section Heights — Refund & Return Policy and Chargeback Waiver sections use a shorter 260px scroll box to visually distinguish them from the primary Terms & Conditions.
Files Changed
- Modified:
templates/js-chunks/approval-info.php,assets/js/app.js
---
[3.6.0.2] — 2026-04-10
Webhook Token Generator
Features
- Token Generator Widget — Added a 16-character random token generator directly below the "Webhook auth token" field on the Settings page. Includes a "Generate Token" button and a clipboard copy icon with visual feedback.
Files Changed
- Modified:
inc/controllers/Settings.php
---
[3.6.0.1] — 2026-04-10
Patch
Changes
- Version bump.
---
[3.6.0.0] — 2026-04-10
Legal Agreements for Auction Approval
Features
- Terms & Conditions — A mandatory, scrollable Terms & Conditions document is now displayed during the auction approval process. Bidders must scroll to the bottom and check an agreement box before their approval request is submitted. Always enabled.
- Refund & Return Policy — An optional, scrollable Refund & Return Policy can be enabled in Settings. When enabled, bidders must read and accept it during auction approval.
- Chargeback Waiver — An optional, scrollable Chargeback Waiver can be enabled in Settings. When enabled, bidders must read and accept it during auction approval.
- Admin Management — New "Legal Agreements" page under the Bidspirit admin menu with tabbed TinyMCE editors for each agreement type. Includes automatic version numbering (incremented on content change) and full version history.
- Consent Logging — Every agreement acceptance is logged to a dedicated database table (
af_user_agreement_log) with the agreement type, version, user email, IP address, user agent, auction ID, and timestamp. - User Tracking Integration — Agreement events (
terms_agreement,refund_agreement,chargeback_waiver) are also recorded in the existing IP tracking system alongside registration, login, and bid events. - Placeholder Content — Default sample content is seeded on plugin activation for all three agreement types.
Settings Added
- Enable Refund & Return Policy — Toggle to require bidders to accept the refund policy during auction approval.
- Enable Chargeback Waiver — Toggle to require bidders to accept the chargeback waiver during auction approval.
Database
- New table:
af_legal_agreements— Current active agreement content per type - New table:
af_legal_agreement_versions— Version history archive - New table:
af_user_agreement_log— User consent records
Files Changed
- Modified:
auctionforge.php,inc/controllers/Settings.php,inc/controllers/BidspiritViews.php,inc/ip-logger.php,templates/js-chunks/approval-info.php,assets/js/app.js - Created:
inc/legal/class-legal-agreements.php,admin/view/legal-agreements.php
---
[3.5.0.6] — 2026-04-08
Bid Event Tracking
Features
- Bid Tracking — All successful bids (regular, catalog, pre-sale buyout, post-sale purchase) now fire
afLogIP("bid", bidspiritUser)to capture the bidder's full identity in the user tracking table. - Whitelist Update — Added
bidto the allowedevent_typevalues in both the local plugin and the central WPDeploy API.
---
[3.5.0.5] — 2026-04-08
Self-Healing Database Schema
Features
- Auto-Migration — The plugin now auto-detects and adds any missing tracking table columns on version upgrade, ensuring sites with older schemas seamlessly migrate without manual SQL.
---
[3.5.0.4] — 2026-04-08
API Key Auto-Healing
Features
- Seamless Self-Registration — The WordPress plugin now autonomously regenerates and saves a fresh API Key whenever WPDeploy rejects a payload with an
api_key_collisionerror. This guarantees zero-downtime security handovers when developers clone instances to proxy/staging servers.
---
[3.5.0.3] — 2026-04-08
API Key Collision Defense
Features
- 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_collisionerrors, directly instructing developers to update cloned keys.
---
[3.5.0.2] — 2026-04-08
Modal Trigger Hotfix
Fixes
- Restructured internal UI rendering priority to gracefully deploy the inline Modal triggers inside custom IP log view without colliding with cached
z-indexstacks.
---
[3.5.0.1] — 2026-04-08
Hotfix
Fixes
- Timed Auction Badge Visibility — Fixed a strict type-matching bug in the main
auction_list.phpcore file that incorrectly hid the "Timed Auction" badge overlay from valid timed/online auctions on the main upcoming/archive views. The badge now displays properly across all manual and Bidspirit-synced objects when toggled on.
Files Changed
- Modified:
templates/main/auction_list.php
---
[3.2.9.1] — 2026-03-30
Timed Auction Display Enhancements
Features
- Timed Auction Countdown Text Toggle — Added a WP-Admin setting "Change text to 'Auction will close in'" that conditionally changes the countdown label for timed/online auctions on single lot pages.
- Shortcode Text Toggle Support — Extended the new countdown text logic to the
bp_upcoming_wideshortcodes so "Live bidding starts in:" successfully transitions to "Auction will close in:" for timed auctions.
Files Changed
- Modified:
inc/controllers/Settings.php,templates/single-lot.php,templates/shortcodes/upcoming-auction-wide.php,templates/shortcodes/upcoming-auction-wide-manual.php
---
[3.2.9.0] — 2026-03-29
Billing & Invoices Polish
Fixes
- Profile Invoice ID Tracking — Prevented internal auction codes (e.g.
002orai4) from breaking into the clean hyphenated titles inside theprofile-templates.phpview. - Dynamic Payment Statuses — Replaced Bidspirit's default/cached
NOT PAIDHTML payloads by wiring thedompdfgenerator to directly respect the current$b.statusstring from the API (resolving instances where a paid invoice still printed "NOT PAID" atop the document). - Payment Instructions Conditional — Automatically hide the "Payment Instructions" block from the PDF footer when an invoice is fully paid.
- Improved Nomenclature — Changed "Invoice No:" to "Bidder No:" on document output to prevent confusion with static invoice ledger IDs.
---
[3.2.6.0] — 2026-03-28
Multi-Day Auction Lot Filtering Fix
Fixes
- Day 2+ showing lots from Day 1 in multi-day auctions — The
itemIndexcolumn inbp_meta_dataisvarchar(55), but the day-range filter inBidspiritQuery::bp_query_where()was comparing it as a string. With string comparison, lot numbers like'11','101'–'145'incorrectly fell between'1001'and'1450', causing Day 1 lots to leak into Day 2 results. Fixed by usingCAST(bpMeta.itemIndex AS UNSIGNED)for numeric comparison andintval()on the PHP-side boundary values. Letter lots (e.g.14A,1025A) are handled correctly —CASTstrips the suffix, keeping them grouped with their base lot number.
Files Changed
- Modified:
inc/controllers/BidspiritQuery.php
---
[3.2.5.9] — 2026-03-27
Catalog Page Fix
Fixes
- Duplicate preview hours on catalog pages — The
displayHoursfield was rendered twice: once via thebp_after_description_auctionhook inBidspiritViews.phpand once inline in the auction template. Removed the hook-based rendering to eliminate the duplication.
Files Changed
- Modified:
inc/controllers/BidspiritViews.php,templates/main/auction.php
---
[3.2.5] — 2026-03-19
Sync Reliability & Stuck Lot Prevention
Fixes
- CATALOG_PUBLISHED webhook now triggers catalog sync — Previously only sent push notifications without syncing lots. When the earlier AUCTION_CATALOG_UPDATED fired before the catalog was ready on BidSpirit, lots were never imported. CATALOG_PUBLISHED now calls
auctionCatalogUpdated()to trigger a full catalog sync when the catalog is actually available. - 0-lot API results now fail instead of silently succeeding — When BidSpirit API returns 0 lots (catalog not yet ready), the sync job now fails with an explicit error message, allowing the next webhook to create a fresh retry job.
- Expanded CDN allowlist in pre_http_request filter — The HTTP filter during bulk post insertion now allows all
*.bidspirit.comsubdomains and BidSpirit image CDNs (fastly.net,cloudfront.net). Previously onlybidspirit.comandwww.bidspirit.comwere allowed, blocking image downloads during sync and causing worker hangs. - InsertLotsBS timeout guard — Stage 5 (InsertLotsBS processing loop) now has a 180-second timeout and logs progress every 2 batches. Prevents indefinite hangs that previously required manual force-kill.
- fixResult() no longer marks lots as done when postId=0 — When
lotProcessing()fails to create a WP post, the staging row now keepssyncFinished=0so the lot is retried on the next sync pass, instead of being permanently marked as complete with no actual post. - lotProcessing() logs error on missing auction term — Previously returned 0 silently when
Auction::findAuctionById()failed. Now logs an explicit error that feeds intofixResult()to keep the lot retryable. - Hourly orphan detection in safety cron — New step in
syncSafety.phpdetects lot posts that exist inbp_meta_databut are missing their auction taxonomy assignment (caused by workers killed mid-batch) and auto-repairs them withwp_set_object_terms().
Files Changed
- Modified:
inc/controllers/AuctionsAPI.php,inc/sync/CatalogSyncWorker.php,inc/abs/InsertLotsAbstract.php,inc/import/InsertLotsBS.php,crontasks/syncSafety.php
---
[3.2.4] — 2026-03-18
Sync Worker Hang Fix
Fixes
- Sync workers hanging at InsertLotsBS stage — Third-party plugins (Smush Pro, SmartCrawl SEO, WPMU DEV Updates) hook into
wp_insert_post()and make blocking outbound HTTPS calls for every lot processed. With 489+ lots per auction, this caused workers to hang indefinitely on socket reads to WPMU DEV servers (32.193.94.25,32.193.93.106). AddedWP_IMPORTINGconstant at the REST worker entry point and apre_http_requestfilter inCatalogSyncWorkerthat blocks all non-essential external HTTP during the batch post-insertion phase. Loopback (127.0.0.1,localhost) and BidSpirit API calls remain allowed. - Stuck staging rows after force-kill — When workers were force-killed mid-sync, staging rows in
import_historywere left withsyncstart=1and never unblocked. Subsequent sync runs could not see these rows (filtered out byLot::getRawLots()), causing the InsertLotsBS loop to exit immediately with 0 posts processed. Combined with job deduplication (SyncQueue::enqueue()skips if aprocessingjob exists), this created a deadlock where no new sync could proceed.
Files Changed
- Modified:
auctionforge.php,inc/sync/CatalogSyncWorker.php
---
[3.2.2] — 2026-03-17
Full Sync Auction Discovery Fix
Fixes
- Full Sync finds no auctions on fresh sites — The v3
full_syncaction only queried the WordPress database for existing auction terms, but on a freshly deployed site the database has zero auctions. AddedAuctionList::init()discovery step before querying the DB, so Full Sync now fetches all auctions from the BidSpirit API and creates taxonomy terms first, then enqueues catalog sync jobs for each.
Files Changed
- Modified:
auctionforge.php
---
[3.2.0] — 2026-03-14
Webhook Pipeline Fixes, Archive Sync & Admin UI Overhaul
New Features
- Archive Sync — New "Archive Sync" button on Sync Status admin page. Enqueues catalog sync jobs for all ARCHIVED/ENDED auctions. Past auctions now appear in the auction dropdown with an optgroup separator and state label.
- Sync Tasks v3 — Replaced old v2 task cards (importData, importBidSpirit, lotBidSpiritOld) with v3 queue-based tasks. "Sync Active Auctions" and "Sync Archived Auctions" now enqueue jobs via the queue system. Maintenance tasks (Clean Draft/Trash Lots, Clean Orphaned Meta) remain as direct-execution tasks.
- How It Works guide rewritten — Complete rewrite of the admin guide for v3 architecture. Documents webhook-first flow, all 5 job types, queue system mechanics, cron setup (external + WP-Cron), configuration constants, and troubleshooting.
Fixes
- Dual-write removed — Removed legacy handlers from
auctionCatalogUpdated(),auctionDayEnded(), anditemsUpdated()webhook methods. The old handlers were racing with the v3 worker, creating orphaned staging rows inimport_historythat were never processed. All three methods now exclusively use the v3 enqueue → spawn path. - ITEMS_UPDATED webhook — Fixed
itemsUpdated()failing to enqueue jobs. TheITEMS_UPDATEDpayload hasauctionIdnested initemsByLanguage.{lang}[0].item.auctionId, not at the top level. Added extraction logic to resolve it. - ItemUpdateWorker incomplete —
ItemUpdateWorker::process()was only callingLot::bulkSave()(staging table) without runningInsertLotsBSto process staged data into WP posts andbp_meta_data. Added the InsertLotsBS processing step with autocommit restore. Item updates now flow: stage → InsertLotsBS → WP post + meta → cache clear. - Worker spawn reliability — Changed
SyncQueue::spawnWorker()from non-blocking HTTPS to blocking HTTP loopback (http://127.0.0.1with explicitHostheader, 2s timeout). Fixes nginx 403/404 errors when HTTPS loopback hits the default vhost instead of the site's vhost. - API token constant — Plugin expects
AUCTIONFORGE_API_TOKENinwp-config.php(renamed fromUCO_API_TOKENduring the plugin rename). Documented in readme.
Database
- DB version: 22 → 23
Files Changed
- Modified:
inc/controllers/AuctionsAPI.php,inc/sync/ItemUpdateWorker.php,inc/sync/SyncQueue.php,auctionforge.php,admin/view/sync-status.php,readme.txt
---
[3.0.0] — 2025-03-14
New Feature: Webhook-First Sync Architecture (Sync v3)
Overview: Complete redesign of the BidSpirit data synchronisation pipeline. Replaces the old two-phase polling system (importBidSpirit every hour + importData every minute) with a webhook-driven job queue that processes data in near real-time.
Architecture
- 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: webhook → queue → background worker → WordPress posts. - Dual-write mode — During transition, webhooks enqueue jobs AND still run the legacy handlers. Once verified, legacy handlers can be removed cleanly.
- Job deduplication — Prevents duplicate work by checking for existing pending/processing jobs with the same auction_id + job_type.
New Components
- Job Queue System (
inc/sync/SyncQueue.php) — Priority-based FIFO queue with atomic job claiming, status tracking (pending/processing/completed/failed/skipped), worker PID tracking, and automatic stuck job recovery. - Sync Logger (
inc/sync/SyncLogger.php) — Real-time log table for admin console polling with level filtering (info/success/warning/error) and incremental cursor-based retrieval. - Catalog Sync Worker (
inc/sync/CatalogSyncWorker.php) — Processes catalog_sync, full_sync, and day_ended jobs by reusing existingLotList::singleRun()logic. - Item Update Worker (
inc/sync/ItemUpdateWorker.php) — Processes individual item_update jobs with the same logic as the webhookitemsUpdatedhandler. - Background Worker (
crontasks/syncWorker.php) — Async CLI process spawned by webhooks viaexec()or by the safety cron. Claims and processes queued jobs with a configurable timeout (default 240s). - Safety Net (
crontasks/syncSafety.php) — Hourly cron that resets stuck jobs (>10min), spawns workers for pending jobs, runs a 24-hour health check (auto-enqueues full sync if no webhooks received), and purges old data.
Admin UI
- Queue Status Dashboard — New card on Sync Status page showing pending/processing/completed/failed/skipped counts, recent jobs table with real-time refresh, worker status badge, and action buttons:
- Full Sync — Enqueues catalog sync for all active auctions
- Sync Selected — Enqueue a single auction from dropdown
- Spawn Worker — Manually trigger a background worker process
- Live Console — Dark-themed terminal console on the Sync Status page. Polls
af_sync_logevery 1.5s showing timestamped, color-coded log entries from webhooks, workers, queue operations, and the safety cron. Supports pause, clear, and auto-scroll.
Cron Changes
- Removed
importData(ran every minute — ~1,440 PHP executions/day) - Removed
importBidSpirit(ran hourly — ~24 PHP executions/day) - Added
syncSafety(runs hourly at :10 — 24 PHP executions/day) - Net effect: ~62 PHP executions/hour → 1 PHP execution/hour
- WP-Cron safety hook (
auctionforge_sync_safety) — Always-active hourly event, independent of external cron - setup.sh v3 — Updated task definitions, new
migratecommand for interactive v2→v3 transition
Database
- New table:
af_sync_queue— Job queue with status, priority, source, attempts, worker PID, timing columns - New table:
af_sync_log— Real-time log entries with context, level, auction_id, job_id - DB version: 20 → 22
Constants Added
| Constant | Default | Description |
|---|---|---|
|
AUCTIONFORGE_SYNC_WORKER_TIMEOUT| 240 | Worker process timeout in seconds ||
AUCTIONFORGE_SYNC_STALE_JOB| 600 | Seconds before a processing job is considered stuck ||
AUCTIONFORGE_SYNC_HEALTH_CHECK| 86400 | Seconds without webhook before triggering full sync ||
AUCTIONFORGE_SYNC_LOG_RETENTION| 7 | Days to keep log entries ||
AUCTIONFORGE_SYNC_QUEUE_RETENTION| 30 | Days to keep completed queue jobs ||
AUCTIONFORGE_CURL_TIMEOUT| 30 | BidSpirit API cURL timeout in seconds ||
AUCTIONFORGE_PHP_BINARY| /www/server/php/83/bin/php | PHP CLI binary path for spawning workers |AJAX Handlers Added
auctionforge_sync_log_poll— Incremental log polling for live consoleauctionforge_sync_queue_status— Queue counts + recent jobs for dashboardauctionforge_sync_enqueue— Admin-triggered sync actions (full_sync, sync_auction, spawn_worker)
Fixes
- cURL timeout — BidSpiritRequest now enforces a 30-second timeout (was unlimited/0), preventing hung connections from blocking the sync pipeline.
Files Changed
- Modified:
auctionforge.php,inc/coreIncludes.php,inc/controllers/AuctionsAPI.php,inc/BidSpiritRequest.php,admin/view/sync-status.php,crontasks/setup.sh - Created:
inc/sync/SyncQueue.php,inc/sync/SyncLogger.php,inc/sync/CatalogSyncWorker.php,inc/sync/ItemUpdateWorker.php,crontasks/syncWorker.php,crontasks/syncSafety.php
---
[2.7.3.0]
Fixes
- Various stability improvements and bug fixes.
[2.7.1.2]
Fixes
- Added missing
vatAndCommission()function inloadBid()— the sales tax display on single lot pages was never being rendered because the code to callloadTemplateforvat-and-commission-templatewas missing fromapp.js.
[2.7.1.1]
Fixes
- 2 decimal places now only appear in the bid modal (Your max bid, Total Price) via
showDecimalsflag. 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.
[2.7.0.9]
Fixes
- Fixed fatal error during plugin install/upgrade:
class-stats-database.phprequire failure.
[2.7.0.0]
New Features: Advanced Lot Analytics
- Conversion Tracking, Peak Viewing Times, Pre-Sale vs Live Comparison, Category Performance, Share Analytics, Search → View Funnel, Click-Through Tracking, CSV Export, Hot Lot Badge.
- New DB table:
af_lot_shares. New columns onaf_lot_analytics. DB version bumped to 20.
[2.6.0.0]
New Feature: Lot Analytics
- Comprehensive lot view and favorite tracking system with admin dashboard.
[2.5.0.0]
New Features
- Site Statistics System — Full website analytics built into the plugin admin.
- Recently Viewed Items — Profile page tab showing last 20 viewed lots per user.
-
v3.6.0.20 Stable Apr 26, 2026Download v3.6.0.20📦 8.95 MB⚙️ WP 5.2+🔧 PHP 7.2+✓ Tested 6.4
AuctionForge Changelog
All notable changes to the AuctionForge plugin are documented in this file.
---
[3.6.0.18] — 2026-04-25
Brevo SMS Notifications Integration
Features
- Transactional SMS via Brevo API — The plugin now sends text message alerts through the Brevo transactional SMS service, running alongside existing Firebase push notifications.
- Four Notification Types:
- New Auction Published — Broadcast SMS to all opted-in subscribers when an auction is published.
- Auction Starting Soon — Targeted SMS to users registered for an auction when it is about to start.
- Favorited Item Live Soon — Targeted SMS to users who favorited a lot when it is approaching in the auction.
- Outbid Notice — SMS sent when a user's leading bid is surpassed, with a 5-minute per-item cooldown to prevent spam.
- SMS Subscriber Database — New
af_sms_subscriberstable stores user phone numbers, country codes, and per-notification-type opt-in preferences (GDPR-ready explicit consent). - Admin Settings Tab — New "SMS Notifications" tab in Settings with:
- Brevo API Key input
- SMS Sender Name (11 char max)
- Master enable/disable toggle
- Per-notification-type on/off switches
- Test SMS widget with phone input and send button
- Live subscriber count display
- Profile SMS Preferences — Users can opt into SMS notifications directly from their profile page with phone number entry and granular notification type selection.
Architecture
- BrevoSMS Service (
inc/services/BrevoSMS.php) — cURL-based API wrapper with broadcast, targeted, and single-send methods, message builders with 160-char limit awareness, rate limiting, and comprehensive error logging. - SMSSubscriber Model (
inc/model/SMSSubscriber.php) — CRUD operations, email-to-phone resolution, opt-in filtering, and upsert logic. - Webhook Integration — SMS dispatch hooks added to
AuctionsAPI.phpmethods:leading_bid_surpassed(),item_live_soon(),auction_starts_soon(), andauctionPublishedPush().
AJAX Handlers
auctionforge_sms_save— Save SMS preferences from profile pageauctionforge_sms_load— Load SMS preferences for profile pageauctionforge_sms_test— Admin-only test SMS endpoint
Database
- New table:
af_sms_subscribers— Phone numbers, country codes, per-notification opt-ins, timestamps
Files Changed
- Modified:
auctionforge.php,inc/coreIncludes.php,inc/controllers/AuctionsAPI.php,inc/controllers/Settings.php,admin/view/settings.php,templates/parts/profile-templates.php - Created:
inc/services/BrevoSMS.php,inc/model/SMSSubscriber.php
---
[3.6.0.7] — 2026-04-14
Hotfix
Fixes
- Namespace resolution — Fixed fatal error in
wp_footercommission label hook caused by unqualifiedSettingsHelperandSettingsclass references. Now uses fully qualified namespaces.
Files Changed
- Modified:
auctionforge.php
---
[3.6.0.6] — 2026-04-14
Commission Label Override Fix
Fixes
- Theme template override compatibility — Moved the commission label JS override from the
single-lot.phptemplate intoauctionforge.phpviawp_footerhook (priority 99). Sites with theme-level template overrides (e.g.themes/*/auctionforge/single-lot.php) were not picking up the inline script. Thewp_footerapproach works universally on all single lot pages.
Files Changed
- Modified:
auctionforge.php,templates/single-lot.php
---
[3.6.0.5] — 2026-04-14
Commission Label Override
Features
- Commission Label Setting — New dropdown in Settings → Appearance allowing admins to choose between "Buyer's Premium" (default) and "Auction House Commission" as the label displayed on lot pages. This overrides the Bidspirit JS client's default label using a MutationObserver that catches asynchronously injected text.
Files Changed
- Modified:
inc/controllers/Settings.php,templates/single-lot.php
---
[3.6.0.4] — 2026-04-12
Auction Approval Modal Redesign
Changes
- Removed BidSpirit Terms of Use — The generic BidSpirit "Terms of Use" section that appeared at the top of the non-credit-card approval modal has been removed. The modal now shows only the auction house's own legal agreements managed within the plugin.
- Renamed Modal Title — Changed "Terms of conditions" to "Terms & Conditions".
- Larger Scroll Area — The Terms & Conditions scroll box is now 350px tall (up from 200px) for easier reading.
- Proportional Section Heights — Refund & Return Policy and Chargeback Waiver sections use a shorter 260px scroll box to visually distinguish them from the primary Terms & Conditions.
Files Changed
- Modified:
templates/js-chunks/approval-info.php,assets/js/app.js
---
[3.6.0.2] — 2026-04-10
Webhook Token Generator
Features
- Token Generator Widget — Added a 16-character random token generator directly below the "Webhook auth token" field on the Settings page. Includes a "Generate Token" button and a clipboard copy icon with visual feedback.
Files Changed
- Modified:
inc/controllers/Settings.php
---
[3.6.0.1] — 2026-04-10
Patch
Changes
- Version bump.
---
[3.6.0.0] — 2026-04-10
Legal Agreements for Auction Approval
Features
- Terms & Conditions — A mandatory, scrollable Terms & Conditions document is now displayed during the auction approval process. Bidders must scroll to the bottom and check an agreement box before their approval request is submitted. Always enabled.
- Refund & Return Policy — An optional, scrollable Refund & Return Policy can be enabled in Settings. When enabled, bidders must read and accept it during auction approval.
- Chargeback Waiver — An optional, scrollable Chargeback Waiver can be enabled in Settings. When enabled, bidders must read and accept it during auction approval.
- Admin Management — New "Legal Agreements" page under the Bidspirit admin menu with tabbed TinyMCE editors for each agreement type. Includes automatic version numbering (incremented on content change) and full version history.
- Consent Logging — Every agreement acceptance is logged to a dedicated database table (
af_user_agreement_log) with the agreement type, version, user email, IP address, user agent, auction ID, and timestamp. - User Tracking Integration — Agreement events (
terms_agreement,refund_agreement,chargeback_waiver) are also recorded in the existing IP tracking system alongside registration, login, and bid events. - Placeholder Content — Default sample content is seeded on plugin activation for all three agreement types.
Settings Added
- Enable Refund & Return Policy — Toggle to require bidders to accept the refund policy during auction approval.
- Enable Chargeback Waiver — Toggle to require bidders to accept the chargeback waiver during auction approval.
Database
- New table:
af_legal_agreements— Current active agreement content per type - New table:
af_legal_agreement_versions— Version history archive - New table:
af_user_agreement_log— User consent records
Files Changed
- Modified:
auctionforge.php,inc/controllers/Settings.php,inc/controllers/BidspiritViews.php,inc/ip-logger.php,templates/js-chunks/approval-info.php,assets/js/app.js - Created:
inc/legal/class-legal-agreements.php,admin/view/legal-agreements.php
---
[3.5.0.6] — 2026-04-08
Bid Event Tracking
Features
- Bid Tracking — All successful bids (regular, catalog, pre-sale buyout, post-sale purchase) now fire
afLogIP("bid", bidspiritUser)to capture the bidder's full identity in the user tracking table. - Whitelist Update — Added
bidto the allowedevent_typevalues in both the local plugin and the central WPDeploy API.
---
[3.5.0.5] — 2026-04-08
Self-Healing Database Schema
Features
- Auto-Migration — The plugin now auto-detects and adds any missing tracking table columns on version upgrade, ensuring sites with older schemas seamlessly migrate without manual SQL.
---
[3.5.0.4] — 2026-04-08
API Key Auto-Healing
Features
- Seamless Self-Registration — The WordPress plugin now autonomously regenerates and saves a fresh API Key whenever WPDeploy rejects a payload with an
api_key_collisionerror. This guarantees zero-downtime security handovers when developers clone instances to proxy/staging servers.
---
[3.5.0.3] — 2026-04-08
API Key Collision Defense
Features
- 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_collisionerrors, directly instructing developers to update cloned keys.
---
[3.5.0.2] — 2026-04-08
Modal Trigger Hotfix
Fixes
- Restructured internal UI rendering priority to gracefully deploy the inline Modal triggers inside custom IP log view without colliding with cached
z-indexstacks.
---
[3.5.0.1] — 2026-04-08
Hotfix
Fixes
- Timed Auction Badge Visibility — Fixed a strict type-matching bug in the main
auction_list.phpcore file that incorrectly hid the "Timed Auction" badge overlay from valid timed/online auctions on the main upcoming/archive views. The badge now displays properly across all manual and Bidspirit-synced objects when toggled on.
Files Changed
- Modified:
templates/main/auction_list.php
---
[3.2.9.1] — 2026-03-30
Timed Auction Display Enhancements
Features
- Timed Auction Countdown Text Toggle — Added a WP-Admin setting "Change text to 'Auction will close in'" that conditionally changes the countdown label for timed/online auctions on single lot pages.
- Shortcode Text Toggle Support — Extended the new countdown text logic to the
bp_upcoming_wideshortcodes so "Live bidding starts in:" successfully transitions to "Auction will close in:" for timed auctions.
Files Changed
- Modified:
inc/controllers/Settings.php,templates/single-lot.php,templates/shortcodes/upcoming-auction-wide.php,templates/shortcodes/upcoming-auction-wide-manual.php
---
[3.2.9.0] — 2026-03-29
Billing & Invoices Polish
Fixes
- Profile Invoice ID Tracking — Prevented internal auction codes (e.g.
002orai4) from breaking into the clean hyphenated titles inside theprofile-templates.phpview. - Dynamic Payment Statuses — Replaced Bidspirit's default/cached
NOT PAIDHTML payloads by wiring thedompdfgenerator to directly respect the current$b.statusstring from the API (resolving instances where a paid invoice still printed "NOT PAID" atop the document). - Payment Instructions Conditional — Automatically hide the "Payment Instructions" block from the PDF footer when an invoice is fully paid.
- Improved Nomenclature — Changed "Invoice No:" to "Bidder No:" on document output to prevent confusion with static invoice ledger IDs.
---
[3.2.6.0] — 2026-03-28
Multi-Day Auction Lot Filtering Fix
Fixes
- Day 2+ showing lots from Day 1 in multi-day auctions — The
itemIndexcolumn inbp_meta_dataisvarchar(55), but the day-range filter inBidspiritQuery::bp_query_where()was comparing it as a string. With string comparison, lot numbers like'11','101'–'145'incorrectly fell between'1001'and'1450', causing Day 1 lots to leak into Day 2 results. Fixed by usingCAST(bpMeta.itemIndex AS UNSIGNED)for numeric comparison andintval()on the PHP-side boundary values. Letter lots (e.g.14A,1025A) are handled correctly —CASTstrips the suffix, keeping them grouped with their base lot number.
Files Changed
- Modified:
inc/controllers/BidspiritQuery.php
---
[3.2.5.9] — 2026-03-27
Catalog Page Fix
Fixes
- Duplicate preview hours on catalog pages — The
displayHoursfield was rendered twice: once via thebp_after_description_auctionhook inBidspiritViews.phpand once inline in the auction template. Removed the hook-based rendering to eliminate the duplication.
Files Changed
- Modified:
inc/controllers/BidspiritViews.php,templates/main/auction.php
---
[3.2.5] — 2026-03-19
Sync Reliability & Stuck Lot Prevention
Fixes
- CATALOG_PUBLISHED webhook now triggers catalog sync — Previously only sent push notifications without syncing lots. When the earlier AUCTION_CATALOG_UPDATED fired before the catalog was ready on BidSpirit, lots were never imported. CATALOG_PUBLISHED now calls
auctionCatalogUpdated()to trigger a full catalog sync when the catalog is actually available. - 0-lot API results now fail instead of silently succeeding — When BidSpirit API returns 0 lots (catalog not yet ready), the sync job now fails with an explicit error message, allowing the next webhook to create a fresh retry job.
- Expanded CDN allowlist in pre_http_request filter — The HTTP filter during bulk post insertion now allows all
*.bidspirit.comsubdomains and BidSpirit image CDNs (fastly.net,cloudfront.net). Previously onlybidspirit.comandwww.bidspirit.comwere allowed, blocking image downloads during sync and causing worker hangs. - InsertLotsBS timeout guard — Stage 5 (InsertLotsBS processing loop) now has a 180-second timeout and logs progress every 2 batches. Prevents indefinite hangs that previously required manual force-kill.
- fixResult() no longer marks lots as done when postId=0 — When
lotProcessing()fails to create a WP post, the staging row now keepssyncFinished=0so the lot is retried on the next sync pass, instead of being permanently marked as complete with no actual post. - lotProcessing() logs error on missing auction term — Previously returned 0 silently when
Auction::findAuctionById()failed. Now logs an explicit error that feeds intofixResult()to keep the lot retryable. - Hourly orphan detection in safety cron — New step in
syncSafety.phpdetects lot posts that exist inbp_meta_databut are missing their auction taxonomy assignment (caused by workers killed mid-batch) and auto-repairs them withwp_set_object_terms().
Files Changed
- Modified:
inc/controllers/AuctionsAPI.php,inc/sync/CatalogSyncWorker.php,inc/abs/InsertLotsAbstract.php,inc/import/InsertLotsBS.php,crontasks/syncSafety.php
---
[3.2.4] — 2026-03-18
Sync Worker Hang Fix
Fixes
- Sync workers hanging at InsertLotsBS stage — Third-party plugins (Smush Pro, SmartCrawl SEO, WPMU DEV Updates) hook into
wp_insert_post()and make blocking outbound HTTPS calls for every lot processed. With 489+ lots per auction, this caused workers to hang indefinitely on socket reads to WPMU DEV servers (32.193.94.25,32.193.93.106). AddedWP_IMPORTINGconstant at the REST worker entry point and apre_http_requestfilter inCatalogSyncWorkerthat blocks all non-essential external HTTP during the batch post-insertion phase. Loopback (127.0.0.1,localhost) and BidSpirit API calls remain allowed. - Stuck staging rows after force-kill — When workers were force-killed mid-sync, staging rows in
import_historywere left withsyncstart=1and never unblocked. Subsequent sync runs could not see these rows (filtered out byLot::getRawLots()), causing the InsertLotsBS loop to exit immediately with 0 posts processed. Combined with job deduplication (SyncQueue::enqueue()skips if aprocessingjob exists), this created a deadlock where no new sync could proceed.
Files Changed
- Modified:
auctionforge.php,inc/sync/CatalogSyncWorker.php
---
[3.2.2] — 2026-03-17
Full Sync Auction Discovery Fix
Fixes
- Full Sync finds no auctions on fresh sites — The v3
full_syncaction only queried the WordPress database for existing auction terms, but on a freshly deployed site the database has zero auctions. AddedAuctionList::init()discovery step before querying the DB, so Full Sync now fetches all auctions from the BidSpirit API and creates taxonomy terms first, then enqueues catalog sync jobs for each.
Files Changed
- Modified:
auctionforge.php
---
[3.2.0] — 2026-03-14
Webhook Pipeline Fixes, Archive Sync & Admin UI Overhaul
New Features
- Archive Sync — New "Archive Sync" button on Sync Status admin page. Enqueues catalog sync jobs for all ARCHIVED/ENDED auctions. Past auctions now appear in the auction dropdown with an optgroup separator and state label.
- Sync Tasks v3 — Replaced old v2 task cards (importData, importBidSpirit, lotBidSpiritOld) with v3 queue-based tasks. "Sync Active Auctions" and "Sync Archived Auctions" now enqueue jobs via the queue system. Maintenance tasks (Clean Draft/Trash Lots, Clean Orphaned Meta) remain as direct-execution tasks.
- How It Works guide rewritten — Complete rewrite of the admin guide for v3 architecture. Documents webhook-first flow, all 5 job types, queue system mechanics, cron setup (external + WP-Cron), configuration constants, and troubleshooting.
Fixes
- Dual-write removed — Removed legacy handlers from
auctionCatalogUpdated(),auctionDayEnded(), anditemsUpdated()webhook methods. The old handlers were racing with the v3 worker, creating orphaned staging rows inimport_historythat were never processed. All three methods now exclusively use the v3 enqueue → spawn path. - ITEMS_UPDATED webhook — Fixed
itemsUpdated()failing to enqueue jobs. TheITEMS_UPDATEDpayload hasauctionIdnested initemsByLanguage.{lang}[0].item.auctionId, not at the top level. Added extraction logic to resolve it. - ItemUpdateWorker incomplete —
ItemUpdateWorker::process()was only callingLot::bulkSave()(staging table) without runningInsertLotsBSto process staged data into WP posts andbp_meta_data. Added the InsertLotsBS processing step with autocommit restore. Item updates now flow: stage → InsertLotsBS → WP post + meta → cache clear. - Worker spawn reliability — Changed
SyncQueue::spawnWorker()from non-blocking HTTPS to blocking HTTP loopback (http://127.0.0.1with explicitHostheader, 2s timeout). Fixes nginx 403/404 errors when HTTPS loopback hits the default vhost instead of the site's vhost. - API token constant — Plugin expects
AUCTIONFORGE_API_TOKENinwp-config.php(renamed fromUCO_API_TOKENduring the plugin rename). Documented in readme.
Database
- DB version: 22 → 23
Files Changed
- Modified:
inc/controllers/AuctionsAPI.php,inc/sync/ItemUpdateWorker.php,inc/sync/SyncQueue.php,auctionforge.php,admin/view/sync-status.php,readme.txt
---
[3.0.0] — 2025-03-14
New Feature: Webhook-First Sync Architecture (Sync v3)
Overview: Complete redesign of the BidSpirit data synchronisation pipeline. Replaces the old two-phase polling system (importBidSpirit every hour + importData every minute) with a webhook-driven job queue that processes data in near real-time.
Architecture
- 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: webhook → queue → background worker → WordPress posts. - Dual-write mode — During transition, webhooks enqueue jobs AND still run the legacy handlers. Once verified, legacy handlers can be removed cleanly.
- Job deduplication — Prevents duplicate work by checking for existing pending/processing jobs with the same auction_id + job_type.
New Components
- Job Queue System (
inc/sync/SyncQueue.php) — Priority-based FIFO queue with atomic job claiming, status tracking (pending/processing/completed/failed/skipped), worker PID tracking, and automatic stuck job recovery. - Sync Logger (
inc/sync/SyncLogger.php) — Real-time log table for admin console polling with level filtering (info/success/warning/error) and incremental cursor-based retrieval. - Catalog Sync Worker (
inc/sync/CatalogSyncWorker.php) — Processes catalog_sync, full_sync, and day_ended jobs by reusing existingLotList::singleRun()logic. - Item Update Worker (
inc/sync/ItemUpdateWorker.php) — Processes individual item_update jobs with the same logic as the webhookitemsUpdatedhandler. - Background Worker (
crontasks/syncWorker.php) — Async CLI process spawned by webhooks viaexec()or by the safety cron. Claims and processes queued jobs with a configurable timeout (default 240s). - Safety Net (
crontasks/syncSafety.php) — Hourly cron that resets stuck jobs (>10min), spawns workers for pending jobs, runs a 24-hour health check (auto-enqueues full sync if no webhooks received), and purges old data.
Admin UI
- Queue Status Dashboard — New card on Sync Status page showing pending/processing/completed/failed/skipped counts, recent jobs table with real-time refresh, worker status badge, and action buttons:
- Full Sync — Enqueues catalog sync for all active auctions
- Sync Selected — Enqueue a single auction from dropdown
- Spawn Worker — Manually trigger a background worker process
- Live Console — Dark-themed terminal console on the Sync Status page. Polls
af_sync_logevery 1.5s showing timestamped, color-coded log entries from webhooks, workers, queue operations, and the safety cron. Supports pause, clear, and auto-scroll.
Cron Changes
- Removed
importData(ran every minute — ~1,440 PHP executions/day) - Removed
importBidSpirit(ran hourly — ~24 PHP executions/day) - Added
syncSafety(runs hourly at :10 — 24 PHP executions/day) - Net effect: ~62 PHP executions/hour → 1 PHP execution/hour
- WP-Cron safety hook (
auctionforge_sync_safety) — Always-active hourly event, independent of external cron - setup.sh v3 — Updated task definitions, new
migratecommand for interactive v2→v3 transition
Database
- New table:
af_sync_queue— Job queue with status, priority, source, attempts, worker PID, timing columns - New table:
af_sync_log— Real-time log entries with context, level, auction_id, job_id - DB version: 20 → 22
Constants Added
| Constant | Default | Description |
|---|---|---|
|
AUCTIONFORGE_SYNC_WORKER_TIMEOUT| 240 | Worker process timeout in seconds ||
AUCTIONFORGE_SYNC_STALE_JOB| 600 | Seconds before a processing job is considered stuck ||
AUCTIONFORGE_SYNC_HEALTH_CHECK| 86400 | Seconds without webhook before triggering full sync ||
AUCTIONFORGE_SYNC_LOG_RETENTION| 7 | Days to keep log entries ||
AUCTIONFORGE_SYNC_QUEUE_RETENTION| 30 | Days to keep completed queue jobs ||
AUCTIONFORGE_CURL_TIMEOUT| 30 | BidSpirit API cURL timeout in seconds ||
AUCTIONFORGE_PHP_BINARY| /www/server/php/83/bin/php | PHP CLI binary path for spawning workers |AJAX Handlers Added
auctionforge_sync_log_poll— Incremental log polling for live consoleauctionforge_sync_queue_status— Queue counts + recent jobs for dashboardauctionforge_sync_enqueue— Admin-triggered sync actions (full_sync, sync_auction, spawn_worker)
Fixes
- cURL timeout — BidSpiritRequest now enforces a 30-second timeout (was unlimited/0), preventing hung connections from blocking the sync pipeline.
Files Changed
- Modified:
auctionforge.php,inc/coreIncludes.php,inc/controllers/AuctionsAPI.php,inc/BidSpiritRequest.php,admin/view/sync-status.php,crontasks/setup.sh - Created:
inc/sync/SyncQueue.php,inc/sync/SyncLogger.php,inc/sync/CatalogSyncWorker.php,inc/sync/ItemUpdateWorker.php,crontasks/syncWorker.php,crontasks/syncSafety.php
---
[2.7.3.0]
Fixes
- Various stability improvements and bug fixes.
[2.7.1.2]
Fixes
- Added missing
vatAndCommission()function inloadBid()— the sales tax display on single lot pages was never being rendered because the code to callloadTemplateforvat-and-commission-templatewas missing fromapp.js.
[2.7.1.1]
Fixes
- 2 decimal places now only appear in the bid modal (Your max bid, Total Price) via
showDecimalsflag. 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.
[2.7.0.9]
Fixes
- Fixed fatal error during plugin install/upgrade:
class-stats-database.phprequire failure.
[2.7.0.0]
New Features: Advanced Lot Analytics
- Conversion Tracking, Peak Viewing Times, Pre-Sale vs Live Comparison, Category Performance, Share Analytics, Search → View Funnel, Click-Through Tracking, CSV Export, Hot Lot Badge.
- New DB table:
af_lot_shares. New columns onaf_lot_analytics. DB version bumped to 20.
[2.6.0.0]
New Feature: Lot Analytics
- Comprehensive lot view and favorite tracking system with admin dashboard.
[2.5.0.0]
New Features
- Site Statistics System — Full website analytics built into the plugin admin.
- Recently Viewed Items — Profile page tab showing last 20 viewed lots per user.
-
v3.6.0.19 Stable Apr 26, 2026Download v3.6.0.19📦 8.95 MB⚙️ WP 5.2+🔧 PHP 7.2+✓ Tested 6.4
AuctionForge Changelog
All notable changes to the AuctionForge plugin are documented in this file.
---
[3.6.0.18] — 2026-04-25
Brevo SMS Notifications Integration
Features
- Transactional SMS via Brevo API — The plugin now sends text message alerts through the Brevo transactional SMS service, running alongside existing Firebase push notifications.
- Four Notification Types:
- New Auction Published — Broadcast SMS to all opted-in subscribers when an auction is published.
- Auction Starting Soon — Targeted SMS to users registered for an auction when it is about to start.
- Favorited Item Live Soon — Targeted SMS to users who favorited a lot when it is approaching in the auction.
- Outbid Notice — SMS sent when a user's leading bid is surpassed, with a 5-minute per-item cooldown to prevent spam.
- SMS Subscriber Database — New
af_sms_subscriberstable stores user phone numbers, country codes, and per-notification-type opt-in preferences (GDPR-ready explicit consent). - Admin Settings Tab — New "SMS Notifications" tab in Settings with:
- Brevo API Key input
- SMS Sender Name (11 char max)
- Master enable/disable toggle
- Per-notification-type on/off switches
- Test SMS widget with phone input and send button
- Live subscriber count display
- Profile SMS Preferences — Users can opt into SMS notifications directly from their profile page with phone number entry and granular notification type selection.
Architecture
- BrevoSMS Service (
inc/services/BrevoSMS.php) — cURL-based API wrapper with broadcast, targeted, and single-send methods, message builders with 160-char limit awareness, rate limiting, and comprehensive error logging. - SMSSubscriber Model (
inc/model/SMSSubscriber.php) — CRUD operations, email-to-phone resolution, opt-in filtering, and upsert logic. - Webhook Integration — SMS dispatch hooks added to
AuctionsAPI.phpmethods:leading_bid_surpassed(),item_live_soon(),auction_starts_soon(), andauctionPublishedPush().
AJAX Handlers
auctionforge_sms_save— Save SMS preferences from profile pageauctionforge_sms_load— Load SMS preferences for profile pageauctionforge_sms_test— Admin-only test SMS endpoint
Database
- New table:
af_sms_subscribers— Phone numbers, country codes, per-notification opt-ins, timestamps
Files Changed
- Modified:
auctionforge.php,inc/coreIncludes.php,inc/controllers/AuctionsAPI.php,inc/controllers/Settings.php,admin/view/settings.php,templates/parts/profile-templates.php - Created:
inc/services/BrevoSMS.php,inc/model/SMSSubscriber.php
---
[3.6.0.7] — 2026-04-14
Hotfix
Fixes
- Namespace resolution — Fixed fatal error in
wp_footercommission label hook caused by unqualifiedSettingsHelperandSettingsclass references. Now uses fully qualified namespaces.
Files Changed
- Modified:
auctionforge.php
---
[3.6.0.6] — 2026-04-14
Commission Label Override Fix
Fixes
- Theme template override compatibility — Moved the commission label JS override from the
single-lot.phptemplate intoauctionforge.phpviawp_footerhook (priority 99). Sites with theme-level template overrides (e.g.themes/*/auctionforge/single-lot.php) were not picking up the inline script. Thewp_footerapproach works universally on all single lot pages.
Files Changed
- Modified:
auctionforge.php,templates/single-lot.php
---
[3.6.0.5] — 2026-04-14
Commission Label Override
Features
- Commission Label Setting — New dropdown in Settings → Appearance allowing admins to choose between "Buyer's Premium" (default) and "Auction House Commission" as the label displayed on lot pages. This overrides the Bidspirit JS client's default label using a MutationObserver that catches asynchronously injected text.
Files Changed
- Modified:
inc/controllers/Settings.php,templates/single-lot.php
---
[3.6.0.4] — 2026-04-12
Auction Approval Modal Redesign
Changes
- Removed BidSpirit Terms of Use — The generic BidSpirit "Terms of Use" section that appeared at the top of the non-credit-card approval modal has been removed. The modal now shows only the auction house's own legal agreements managed within the plugin.
- Renamed Modal Title — Changed "Terms of conditions" to "Terms & Conditions".
- Larger Scroll Area — The Terms & Conditions scroll box is now 350px tall (up from 200px) for easier reading.
- Proportional Section Heights — Refund & Return Policy and Chargeback Waiver sections use a shorter 260px scroll box to visually distinguish them from the primary Terms & Conditions.
Files Changed
- Modified:
templates/js-chunks/approval-info.php,assets/js/app.js
---
[3.6.0.2] — 2026-04-10
Webhook Token Generator
Features
- Token Generator Widget — Added a 16-character random token generator directly below the "Webhook auth token" field on the Settings page. Includes a "Generate Token" button and a clipboard copy icon with visual feedback.
Files Changed
- Modified:
inc/controllers/Settings.php
---
[3.6.0.1] — 2026-04-10
Patch
Changes
- Version bump.
---
[3.6.0.0] — 2026-04-10
Legal Agreements for Auction Approval
Features
- Terms & Conditions — A mandatory, scrollable Terms & Conditions document is now displayed during the auction approval process. Bidders must scroll to the bottom and check an agreement box before their approval request is submitted. Always enabled.
- Refund & Return Policy — An optional, scrollable Refund & Return Policy can be enabled in Settings. When enabled, bidders must read and accept it during auction approval.
- Chargeback Waiver — An optional, scrollable Chargeback Waiver can be enabled in Settings. When enabled, bidders must read and accept it during auction approval.
- Admin Management — New "Legal Agreements" page under the Bidspirit admin menu with tabbed TinyMCE editors for each agreement type. Includes automatic version numbering (incremented on content change) and full version history.
- Consent Logging — Every agreement acceptance is logged to a dedicated database table (
af_user_agreement_log) with the agreement type, version, user email, IP address, user agent, auction ID, and timestamp. - User Tracking Integration — Agreement events (
terms_agreement,refund_agreement,chargeback_waiver) are also recorded in the existing IP tracking system alongside registration, login, and bid events. - Placeholder Content — Default sample content is seeded on plugin activation for all three agreement types.
Settings Added
- Enable Refund & Return Policy — Toggle to require bidders to accept the refund policy during auction approval.
- Enable Chargeback Waiver — Toggle to require bidders to accept the chargeback waiver during auction approval.
Database
- New table:
af_legal_agreements— Current active agreement content per type - New table:
af_legal_agreement_versions— Version history archive - New table:
af_user_agreement_log— User consent records
Files Changed
- Modified:
auctionforge.php,inc/controllers/Settings.php,inc/controllers/BidspiritViews.php,inc/ip-logger.php,templates/js-chunks/approval-info.php,assets/js/app.js - Created:
inc/legal/class-legal-agreements.php,admin/view/legal-agreements.php
---
[3.5.0.6] — 2026-04-08
Bid Event Tracking
Features
- Bid Tracking — All successful bids (regular, catalog, pre-sale buyout, post-sale purchase) now fire
afLogIP("bid", bidspiritUser)to capture the bidder's full identity in the user tracking table. - Whitelist Update — Added
bidto the allowedevent_typevalues in both the local plugin and the central WPDeploy API.
---
[3.5.0.5] — 2026-04-08
Self-Healing Database Schema
Features
- Auto-Migration — The plugin now auto-detects and adds any missing tracking table columns on version upgrade, ensuring sites with older schemas seamlessly migrate without manual SQL.
---
[3.5.0.4] — 2026-04-08
API Key Auto-Healing
Features
- Seamless Self-Registration — The WordPress plugin now autonomously regenerates and saves a fresh API Key whenever WPDeploy rejects a payload with an
api_key_collisionerror. This guarantees zero-downtime security handovers when developers clone instances to proxy/staging servers.
---
[3.5.0.3] — 2026-04-08
API Key Collision Defense
Features
- 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_collisionerrors, directly instructing developers to update cloned keys.
---
[3.5.0.2] — 2026-04-08
Modal Trigger Hotfix
Fixes
- Restructured internal UI rendering priority to gracefully deploy the inline Modal triggers inside custom IP log view without colliding with cached
z-indexstacks.
---
[3.5.0.1] — 2026-04-08
Hotfix
Fixes
- Timed Auction Badge Visibility — Fixed a strict type-matching bug in the main
auction_list.phpcore file that incorrectly hid the "Timed Auction" badge overlay from valid timed/online auctions on the main upcoming/archive views. The badge now displays properly across all manual and Bidspirit-synced objects when toggled on.
Files Changed
- Modified:
templates/main/auction_list.php
---
[3.2.9.1] — 2026-03-30
Timed Auction Display Enhancements
Features
- Timed Auction Countdown Text Toggle — Added a WP-Admin setting "Change text to 'Auction will close in'" that conditionally changes the countdown label for timed/online auctions on single lot pages.
- Shortcode Text Toggle Support — Extended the new countdown text logic to the
bp_upcoming_wideshortcodes so "Live bidding starts in:" successfully transitions to "Auction will close in:" for timed auctions.
Files Changed
- Modified:
inc/controllers/Settings.php,templates/single-lot.php,templates/shortcodes/upcoming-auction-wide.php,templates/shortcodes/upcoming-auction-wide-manual.php
---
[3.2.9.0] — 2026-03-29
Billing & Invoices Polish
Fixes
- Profile Invoice ID Tracking — Prevented internal auction codes (e.g.
002orai4) from breaking into the clean hyphenated titles inside theprofile-templates.phpview. - Dynamic Payment Statuses — Replaced Bidspirit's default/cached
NOT PAIDHTML payloads by wiring thedompdfgenerator to directly respect the current$b.statusstring from the API (resolving instances where a paid invoice still printed "NOT PAID" atop the document). - Payment Instructions Conditional — Automatically hide the "Payment Instructions" block from the PDF footer when an invoice is fully paid.
- Improved Nomenclature — Changed "Invoice No:" to "Bidder No:" on document output to prevent confusion with static invoice ledger IDs.
---
[3.2.6.0] — 2026-03-28
Multi-Day Auction Lot Filtering Fix
Fixes
- Day 2+ showing lots from Day 1 in multi-day auctions — The
itemIndexcolumn inbp_meta_dataisvarchar(55), but the day-range filter inBidspiritQuery::bp_query_where()was comparing it as a string. With string comparison, lot numbers like'11','101'–'145'incorrectly fell between'1001'and'1450', causing Day 1 lots to leak into Day 2 results. Fixed by usingCAST(bpMeta.itemIndex AS UNSIGNED)for numeric comparison andintval()on the PHP-side boundary values. Letter lots (e.g.14A,1025A) are handled correctly —CASTstrips the suffix, keeping them grouped with their base lot number.
Files Changed
- Modified:
inc/controllers/BidspiritQuery.php
---
[3.2.5.9] — 2026-03-27
Catalog Page Fix
Fixes
- Duplicate preview hours on catalog pages — The
displayHoursfield was rendered twice: once via thebp_after_description_auctionhook inBidspiritViews.phpand once inline in the auction template. Removed the hook-based rendering to eliminate the duplication.
Files Changed
- Modified:
inc/controllers/BidspiritViews.php,templates/main/auction.php
---
[3.2.5] — 2026-03-19
Sync Reliability & Stuck Lot Prevention
Fixes
- CATALOG_PUBLISHED webhook now triggers catalog sync — Previously only sent push notifications without syncing lots. When the earlier AUCTION_CATALOG_UPDATED fired before the catalog was ready on BidSpirit, lots were never imported. CATALOG_PUBLISHED now calls
auctionCatalogUpdated()to trigger a full catalog sync when the catalog is actually available. - 0-lot API results now fail instead of silently succeeding — When BidSpirit API returns 0 lots (catalog not yet ready), the sync job now fails with an explicit error message, allowing the next webhook to create a fresh retry job.
- Expanded CDN allowlist in pre_http_request filter — The HTTP filter during bulk post insertion now allows all
*.bidspirit.comsubdomains and BidSpirit image CDNs (fastly.net,cloudfront.net). Previously onlybidspirit.comandwww.bidspirit.comwere allowed, blocking image downloads during sync and causing worker hangs. - InsertLotsBS timeout guard — Stage 5 (InsertLotsBS processing loop) now has a 180-second timeout and logs progress every 2 batches. Prevents indefinite hangs that previously required manual force-kill.
- fixResult() no longer marks lots as done when postId=0 — When
lotProcessing()fails to create a WP post, the staging row now keepssyncFinished=0so the lot is retried on the next sync pass, instead of being permanently marked as complete with no actual post. - lotProcessing() logs error on missing auction term — Previously returned 0 silently when
Auction::findAuctionById()failed. Now logs an explicit error that feeds intofixResult()to keep the lot retryable. - Hourly orphan detection in safety cron — New step in
syncSafety.phpdetects lot posts that exist inbp_meta_databut are missing their auction taxonomy assignment (caused by workers killed mid-batch) and auto-repairs them withwp_set_object_terms().
Files Changed
- Modified:
inc/controllers/AuctionsAPI.php,inc/sync/CatalogSyncWorker.php,inc/abs/InsertLotsAbstract.php,inc/import/InsertLotsBS.php,crontasks/syncSafety.php
---
[3.2.4] — 2026-03-18
Sync Worker Hang Fix
Fixes
- Sync workers hanging at InsertLotsBS stage — Third-party plugins (Smush Pro, SmartCrawl SEO, WPMU DEV Updates) hook into
wp_insert_post()and make blocking outbound HTTPS calls for every lot processed. With 489+ lots per auction, this caused workers to hang indefinitely on socket reads to WPMU DEV servers (32.193.94.25,32.193.93.106). AddedWP_IMPORTINGconstant at the REST worker entry point and apre_http_requestfilter inCatalogSyncWorkerthat blocks all non-essential external HTTP during the batch post-insertion phase. Loopback (127.0.0.1,localhost) and BidSpirit API calls remain allowed. - Stuck staging rows after force-kill — When workers were force-killed mid-sync, staging rows in
import_historywere left withsyncstart=1and never unblocked. Subsequent sync runs could not see these rows (filtered out byLot::getRawLots()), causing the InsertLotsBS loop to exit immediately with 0 posts processed. Combined with job deduplication (SyncQueue::enqueue()skips if aprocessingjob exists), this created a deadlock where no new sync could proceed.
Files Changed
- Modified:
auctionforge.php,inc/sync/CatalogSyncWorker.php
---
[3.2.2] — 2026-03-17
Full Sync Auction Discovery Fix
Fixes
- Full Sync finds no auctions on fresh sites — The v3
full_syncaction only queried the WordPress database for existing auction terms, but on a freshly deployed site the database has zero auctions. AddedAuctionList::init()discovery step before querying the DB, so Full Sync now fetches all auctions from the BidSpirit API and creates taxonomy terms first, then enqueues catalog sync jobs for each.
Files Changed
- Modified:
auctionforge.php
---
[3.2.0] — 2026-03-14
Webhook Pipeline Fixes, Archive Sync & Admin UI Overhaul
New Features
- Archive Sync — New "Archive Sync" button on Sync Status admin page. Enqueues catalog sync jobs for all ARCHIVED/ENDED auctions. Past auctions now appear in the auction dropdown with an optgroup separator and state label.
- Sync Tasks v3 — Replaced old v2 task cards (importData, importBidSpirit, lotBidSpiritOld) with v3 queue-based tasks. "Sync Active Auctions" and "Sync Archived Auctions" now enqueue jobs via the queue system. Maintenance tasks (Clean Draft/Trash Lots, Clean Orphaned Meta) remain as direct-execution tasks.
- How It Works guide rewritten — Complete rewrite of the admin guide for v3 architecture. Documents webhook-first flow, all 5 job types, queue system mechanics, cron setup (external + WP-Cron), configuration constants, and troubleshooting.
Fixes
- Dual-write removed — Removed legacy handlers from
auctionCatalogUpdated(),auctionDayEnded(), anditemsUpdated()webhook methods. The old handlers were racing with the v3 worker, creating orphaned staging rows inimport_historythat were never processed. All three methods now exclusively use the v3 enqueue → spawn path. - ITEMS_UPDATED webhook — Fixed
itemsUpdated()failing to enqueue jobs. TheITEMS_UPDATEDpayload hasauctionIdnested initemsByLanguage.{lang}[0].item.auctionId, not at the top level. Added extraction logic to resolve it. - ItemUpdateWorker incomplete —
ItemUpdateWorker::process()was only callingLot::bulkSave()(staging table) without runningInsertLotsBSto process staged data into WP posts andbp_meta_data. Added the InsertLotsBS processing step with autocommit restore. Item updates now flow: stage → InsertLotsBS → WP post + meta → cache clear. - Worker spawn reliability — Changed
SyncQueue::spawnWorker()from non-blocking HTTPS to blocking HTTP loopback (http://127.0.0.1with explicitHostheader, 2s timeout). Fixes nginx 403/404 errors when HTTPS loopback hits the default vhost instead of the site's vhost. - API token constant — Plugin expects
AUCTIONFORGE_API_TOKENinwp-config.php(renamed fromUCO_API_TOKENduring the plugin rename). Documented in readme.
Database
- DB version: 22 → 23
Files Changed
- Modified:
inc/controllers/AuctionsAPI.php,inc/sync/ItemUpdateWorker.php,inc/sync/SyncQueue.php,auctionforge.php,admin/view/sync-status.php,readme.txt
---
[3.0.0] — 2025-03-14
New Feature: Webhook-First Sync Architecture (Sync v3)
Overview: Complete redesign of the BidSpirit data synchronisation pipeline. Replaces the old two-phase polling system (importBidSpirit every hour + importData every minute) with a webhook-driven job queue that processes data in near real-time.
Architecture
- 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: webhook → queue → background worker → WordPress posts. - Dual-write mode — During transition, webhooks enqueue jobs AND still run the legacy handlers. Once verified, legacy handlers can be removed cleanly.
- Job deduplication — Prevents duplicate work by checking for existing pending/processing jobs with the same auction_id + job_type.
New Components
- Job Queue System (
inc/sync/SyncQueue.php) — Priority-based FIFO queue with atomic job claiming, status tracking (pending/processing/completed/failed/skipped), worker PID tracking, and automatic stuck job recovery. - Sync Logger (
inc/sync/SyncLogger.php) — Real-time log table for admin console polling with level filtering (info/success/warning/error) and incremental cursor-based retrieval. - Catalog Sync Worker (
inc/sync/CatalogSyncWorker.php) — Processes catalog_sync, full_sync, and day_ended jobs by reusing existingLotList::singleRun()logic. - Item Update Worker (
inc/sync/ItemUpdateWorker.php) — Processes individual item_update jobs with the same logic as the webhookitemsUpdatedhandler. - Background Worker (
crontasks/syncWorker.php) — Async CLI process spawned by webhooks viaexec()or by the safety cron. Claims and processes queued jobs with a configurable timeout (default 240s). - Safety Net (
crontasks/syncSafety.php) — Hourly cron that resets stuck jobs (>10min), spawns workers for pending jobs, runs a 24-hour health check (auto-enqueues full sync if no webhooks received), and purges old data.
Admin UI
- Queue Status Dashboard — New card on Sync Status page showing pending/processing/completed/failed/skipped counts, recent jobs table with real-time refresh, worker status badge, and action buttons:
- Full Sync — Enqueues catalog sync for all active auctions
- Sync Selected — Enqueue a single auction from dropdown
- Spawn Worker — Manually trigger a background worker process
- Live Console — Dark-themed terminal console on the Sync Status page. Polls
af_sync_logevery 1.5s showing timestamped, color-coded log entries from webhooks, workers, queue operations, and the safety cron. Supports pause, clear, and auto-scroll.
Cron Changes
- Removed
importData(ran every minute — ~1,440 PHP executions/day) - Removed
importBidSpirit(ran hourly — ~24 PHP executions/day) - Added
syncSafety(runs hourly at :10 — 24 PHP executions/day) - Net effect: ~62 PHP executions/hour → 1 PHP execution/hour
- WP-Cron safety hook (
auctionforge_sync_safety) — Always-active hourly event, independent of external cron - setup.sh v3 — Updated task definitions, new
migratecommand for interactive v2→v3 transition
Database
- New table:
af_sync_queue— Job queue with status, priority, source, attempts, worker PID, timing columns - New table:
af_sync_log— Real-time log entries with context, level, auction_id, job_id - DB version: 20 → 22
Constants Added
| Constant | Default | Description |
|---|---|---|
|
AUCTIONFORGE_SYNC_WORKER_TIMEOUT| 240 | Worker process timeout in seconds ||
AUCTIONFORGE_SYNC_STALE_JOB| 600 | Seconds before a processing job is considered stuck ||
AUCTIONFORGE_SYNC_HEALTH_CHECK| 86400 | Seconds without webhook before triggering full sync ||
AUCTIONFORGE_SYNC_LOG_RETENTION| 7 | Days to keep log entries ||
AUCTIONFORGE_SYNC_QUEUE_RETENTION| 30 | Days to keep completed queue jobs ||
AUCTIONFORGE_CURL_TIMEOUT| 30 | BidSpirit API cURL timeout in seconds ||
AUCTIONFORGE_PHP_BINARY| /www/server/php/83/bin/php | PHP CLI binary path for spawning workers |AJAX Handlers Added
auctionforge_sync_log_poll— Incremental log polling for live consoleauctionforge_sync_queue_status— Queue counts + recent jobs for dashboardauctionforge_sync_enqueue— Admin-triggered sync actions (full_sync, sync_auction, spawn_worker)
Fixes
- cURL timeout — BidSpiritRequest now enforces a 30-second timeout (was unlimited/0), preventing hung connections from blocking the sync pipeline.
Files Changed
- Modified:
auctionforge.php,inc/coreIncludes.php,inc/controllers/AuctionsAPI.php,inc/BidSpiritRequest.php,admin/view/sync-status.php,crontasks/setup.sh - Created:
inc/sync/SyncQueue.php,inc/sync/SyncLogger.php,inc/sync/CatalogSyncWorker.php,inc/sync/ItemUpdateWorker.php,crontasks/syncWorker.php,crontasks/syncSafety.php
---
[2.7.3.0]
Fixes
- Various stability improvements and bug fixes.
[2.7.1.2]
Fixes
- Added missing
vatAndCommission()function inloadBid()— the sales tax display on single lot pages was never being rendered because the code to callloadTemplateforvat-and-commission-templatewas missing fromapp.js.
[2.7.1.1]
Fixes
- 2 decimal places now only appear in the bid modal (Your max bid, Total Price) via
showDecimalsflag. 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.
[2.7.0.9]
Fixes
- Fixed fatal error during plugin install/upgrade:
class-stats-database.phprequire failure.
[2.7.0.0]
New Features: Advanced Lot Analytics
- Conversion Tracking, Peak Viewing Times, Pre-Sale vs Live Comparison, Category Performance, Share Analytics, Search → View Funnel, Click-Through Tracking, CSV Export, Hot Lot Badge.
- New DB table:
af_lot_shares. New columns onaf_lot_analytics. DB version bumped to 20.
[2.6.0.0]
New Feature: Lot Analytics
- Comprehensive lot view and favorite tracking system with admin dashboard.
[2.5.0.0]
New Features
- Site Statistics System — Full website analytics built into the plugin admin.
- Recently Viewed Items — Profile page tab showing last 20 viewed lots per user.
-
v3.6.0.18 Stable Apr 25, 2026Download v3.6.0.18📦 8.94 MB⚙️ WP 5.2+🔧 PHP 7.2+✓ Tested 6.4
AuctionForge Changelog
All notable changes to the AuctionForge plugin are documented in this file.
---
[3.6.0.7] — 2026-04-14
Hotfix
Fixes
- Namespace resolution — Fixed fatal error in
wp_footercommission label hook caused by unqualifiedSettingsHelperandSettingsclass references. Now uses fully qualified namespaces.
Files Changed
- Modified:
auctionforge.php
---
[3.6.0.6] — 2026-04-14
Commission Label Override Fix
Fixes
- Theme template override compatibility — Moved the commission label JS override from the
single-lot.phptemplate intoauctionforge.phpviawp_footerhook (priority 99). Sites with theme-level template overrides (e.g.themes/*/auctionforge/single-lot.php) were not picking up the inline script. Thewp_footerapproach works universally on all single lot pages.
Files Changed
- Modified:
auctionforge.php,templates/single-lot.php
---
[3.6.0.5] — 2026-04-14
Commission Label Override
Features
- Commission Label Setting — New dropdown in Settings → Appearance allowing admins to choose between "Buyer's Premium" (default) and "Auction House Commission" as the label displayed on lot pages. This overrides the Bidspirit JS client's default label using a MutationObserver that catches asynchronously injected text.
Files Changed
- Modified:
inc/controllers/Settings.php,templates/single-lot.php
---
[3.6.0.4] — 2026-04-12
Auction Approval Modal Redesign
Changes
- Removed BidSpirit Terms of Use — The generic BidSpirit "Terms of Use" section that appeared at the top of the non-credit-card approval modal has been removed. The modal now shows only the auction house's own legal agreements managed within the plugin.
- Renamed Modal Title — Changed "Terms of conditions" to "Terms & Conditions".
- Larger Scroll Area — The Terms & Conditions scroll box is now 350px tall (up from 200px) for easier reading.
- Proportional Section Heights — Refund & Return Policy and Chargeback Waiver sections use a shorter 260px scroll box to visually distinguish them from the primary Terms & Conditions.
Files Changed
- Modified:
templates/js-chunks/approval-info.php,assets/js/app.js
---
[3.6.0.2] — 2026-04-10
Webhook Token Generator
Features
- Token Generator Widget — Added a 16-character random token generator directly below the "Webhook auth token" field on the Settings page. Includes a "Generate Token" button and a clipboard copy icon with visual feedback.
Files Changed
- Modified:
inc/controllers/Settings.php
---
[3.6.0.1] — 2026-04-10
Patch
Changes
- Version bump.
---
[3.6.0.0] — 2026-04-10
Legal Agreements for Auction Approval
Features
- Terms & Conditions — A mandatory, scrollable Terms & Conditions document is now displayed during the auction approval process. Bidders must scroll to the bottom and check an agreement box before their approval request is submitted. Always enabled.
- Refund & Return Policy — An optional, scrollable Refund & Return Policy can be enabled in Settings. When enabled, bidders must read and accept it during auction approval.
- Chargeback Waiver — An optional, scrollable Chargeback Waiver can be enabled in Settings. When enabled, bidders must read and accept it during auction approval.
- Admin Management — New "Legal Agreements" page under the Bidspirit admin menu with tabbed TinyMCE editors for each agreement type. Includes automatic version numbering (incremented on content change) and full version history.
- Consent Logging — Every agreement acceptance is logged to a dedicated database table (
af_user_agreement_log) with the agreement type, version, user email, IP address, user agent, auction ID, and timestamp. - User Tracking Integration — Agreement events (
terms_agreement,refund_agreement,chargeback_waiver) are also recorded in the existing IP tracking system alongside registration, login, and bid events. - Placeholder Content — Default sample content is seeded on plugin activation for all three agreement types.
Settings Added
- Enable Refund & Return Policy — Toggle to require bidders to accept the refund policy during auction approval.
- Enable Chargeback Waiver — Toggle to require bidders to accept the chargeback waiver during auction approval.
Database
- New table:
af_legal_agreements— Current active agreement content per type - New table:
af_legal_agreement_versions— Version history archive - New table:
af_user_agreement_log— User consent records
Files Changed
- Modified:
auctionforge.php,inc/controllers/Settings.php,inc/controllers/BidspiritViews.php,inc/ip-logger.php,templates/js-chunks/approval-info.php,assets/js/app.js - Created:
inc/legal/class-legal-agreements.php,admin/view/legal-agreements.php
---
[3.5.0.6] — 2026-04-08
Bid Event Tracking
Features
- Bid Tracking — All successful bids (regular, catalog, pre-sale buyout, post-sale purchase) now fire
afLogIP("bid", bidspiritUser)to capture the bidder's full identity in the user tracking table. - Whitelist Update — Added
bidto the allowedevent_typevalues in both the local plugin and the central WPDeploy API.
---
[3.5.0.5] — 2026-04-08
Self-Healing Database Schema
Features
- Auto-Migration — The plugin now auto-detects and adds any missing tracking table columns on version upgrade, ensuring sites with older schemas seamlessly migrate without manual SQL.
---
[3.5.0.4] — 2026-04-08
API Key Auto-Healing
Features
- Seamless Self-Registration — The WordPress plugin now autonomously regenerates and saves a fresh API Key whenever WPDeploy rejects a payload with an
api_key_collisionerror. This guarantees zero-downtime security handovers when developers clone instances to proxy/staging servers.
---
[3.5.0.3] — 2026-04-08
API Key Collision Defense
Features
- 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_collisionerrors, directly instructing developers to update cloned keys.
---
[3.5.0.2] — 2026-04-08
Modal Trigger Hotfix
Fixes
- Restructured internal UI rendering priority to gracefully deploy the inline Modal triggers inside custom IP log view without colliding with cached
z-indexstacks.
---
[3.5.0.1] — 2026-04-08
Hotfix
Fixes
- Timed Auction Badge Visibility — Fixed a strict type-matching bug in the main
auction_list.phpcore file that incorrectly hid the "Timed Auction" badge overlay from valid timed/online auctions on the main upcoming/archive views. The badge now displays properly across all manual and Bidspirit-synced objects when toggled on.
Files Changed
- Modified:
templates/main/auction_list.php
---
[3.2.9.1] — 2026-03-30
Timed Auction Display Enhancements
Features
- Timed Auction Countdown Text Toggle — Added a WP-Admin setting "Change text to 'Auction will close in'" that conditionally changes the countdown label for timed/online auctions on single lot pages.
- Shortcode Text Toggle Support — Extended the new countdown text logic to the
bp_upcoming_wideshortcodes so "Live bidding starts in:" successfully transitions to "Auction will close in:" for timed auctions.
Files Changed
- Modified:
inc/controllers/Settings.php,templates/single-lot.php,templates/shortcodes/upcoming-auction-wide.php,templates/shortcodes/upcoming-auction-wide-manual.php
---
[3.2.9.0] — 2026-03-29
Billing & Invoices Polish
Fixes
- Profile Invoice ID Tracking — Prevented internal auction codes (e.g.
002orai4) from breaking into the clean hyphenated titles inside theprofile-templates.phpview. - Dynamic Payment Statuses — Replaced Bidspirit's default/cached
NOT PAIDHTML payloads by wiring thedompdfgenerator to directly respect the current$b.statusstring from the API (resolving instances where a paid invoice still printed "NOT PAID" atop the document). - Payment Instructions Conditional — Automatically hide the "Payment Instructions" block from the PDF footer when an invoice is fully paid.
- Improved Nomenclature — Changed "Invoice No:" to "Bidder No:" on document output to prevent confusion with static invoice ledger IDs.
---
[3.2.6.0] — 2026-03-28
Multi-Day Auction Lot Filtering Fix
Fixes
- Day 2+ showing lots from Day 1 in multi-day auctions — The
itemIndexcolumn inbp_meta_dataisvarchar(55), but the day-range filter inBidspiritQuery::bp_query_where()was comparing it as a string. With string comparison, lot numbers like'11','101'–'145'incorrectly fell between'1001'and'1450', causing Day 1 lots to leak into Day 2 results. Fixed by usingCAST(bpMeta.itemIndex AS UNSIGNED)for numeric comparison andintval()on the PHP-side boundary values. Letter lots (e.g.14A,1025A) are handled correctly —CASTstrips the suffix, keeping them grouped with their base lot number.
Files Changed
- Modified:
inc/controllers/BidspiritQuery.php
---
[3.2.5.9] — 2026-03-27
Catalog Page Fix
Fixes
- Duplicate preview hours on catalog pages — The
displayHoursfield was rendered twice: once via thebp_after_description_auctionhook inBidspiritViews.phpand once inline in the auction template. Removed the hook-based rendering to eliminate the duplication.
Files Changed
- Modified:
inc/controllers/BidspiritViews.php,templates/main/auction.php
---
[3.2.5] — 2026-03-19
Sync Reliability & Stuck Lot Prevention
Fixes
- CATALOG_PUBLISHED webhook now triggers catalog sync — Previously only sent push notifications without syncing lots. When the earlier AUCTION_CATALOG_UPDATED fired before the catalog was ready on BidSpirit, lots were never imported. CATALOG_PUBLISHED now calls
auctionCatalogUpdated()to trigger a full catalog sync when the catalog is actually available. - 0-lot API results now fail instead of silently succeeding — When BidSpirit API returns 0 lots (catalog not yet ready), the sync job now fails with an explicit error message, allowing the next webhook to create a fresh retry job.
- Expanded CDN allowlist in pre_http_request filter — The HTTP filter during bulk post insertion now allows all
*.bidspirit.comsubdomains and BidSpirit image CDNs (fastly.net,cloudfront.net). Previously onlybidspirit.comandwww.bidspirit.comwere allowed, blocking image downloads during sync and causing worker hangs. - InsertLotsBS timeout guard — Stage 5 (InsertLotsBS processing loop) now has a 180-second timeout and logs progress every 2 batches. Prevents indefinite hangs that previously required manual force-kill.
- fixResult() no longer marks lots as done when postId=0 — When
lotProcessing()fails to create a WP post, the staging row now keepssyncFinished=0so the lot is retried on the next sync pass, instead of being permanently marked as complete with no actual post. - lotProcessing() logs error on missing auction term — Previously returned 0 silently when
Auction::findAuctionById()failed. Now logs an explicit error that feeds intofixResult()to keep the lot retryable. - Hourly orphan detection in safety cron — New step in
syncSafety.phpdetects lot posts that exist inbp_meta_databut are missing their auction taxonomy assignment (caused by workers killed mid-batch) and auto-repairs them withwp_set_object_terms().
Files Changed
- Modified:
inc/controllers/AuctionsAPI.php,inc/sync/CatalogSyncWorker.php,inc/abs/InsertLotsAbstract.php,inc/import/InsertLotsBS.php,crontasks/syncSafety.php
---
[3.2.4] — 2026-03-18
Sync Worker Hang Fix
Fixes
- Sync workers hanging at InsertLotsBS stage — Third-party plugins (Smush Pro, SmartCrawl SEO, WPMU DEV Updates) hook into
wp_insert_post()and make blocking outbound HTTPS calls for every lot processed. With 489+ lots per auction, this caused workers to hang indefinitely on socket reads to WPMU DEV servers (32.193.94.25,32.193.93.106). AddedWP_IMPORTINGconstant at the REST worker entry point and apre_http_requestfilter inCatalogSyncWorkerthat blocks all non-essential external HTTP during the batch post-insertion phase. Loopback (127.0.0.1,localhost) and BidSpirit API calls remain allowed. - Stuck staging rows after force-kill — When workers were force-killed mid-sync, staging rows in
import_historywere left withsyncstart=1and never unblocked. Subsequent sync runs could not see these rows (filtered out byLot::getRawLots()), causing the InsertLotsBS loop to exit immediately with 0 posts processed. Combined with job deduplication (SyncQueue::enqueue()skips if aprocessingjob exists), this created a deadlock where no new sync could proceed.
Files Changed
- Modified:
auctionforge.php,inc/sync/CatalogSyncWorker.php
---
[3.2.2] — 2026-03-17
Full Sync Auction Discovery Fix
Fixes
- Full Sync finds no auctions on fresh sites — The v3
full_syncaction only queried the WordPress database for existing auction terms, but on a freshly deployed site the database has zero auctions. AddedAuctionList::init()discovery step before querying the DB, so Full Sync now fetches all auctions from the BidSpirit API and creates taxonomy terms first, then enqueues catalog sync jobs for each.
Files Changed
- Modified:
auctionforge.php
---
[3.2.0] — 2026-03-14
Webhook Pipeline Fixes, Archive Sync & Admin UI Overhaul
New Features
- Archive Sync — New "Archive Sync" button on Sync Status admin page. Enqueues catalog sync jobs for all ARCHIVED/ENDED auctions. Past auctions now appear in the auction dropdown with an optgroup separator and state label.
- Sync Tasks v3 — Replaced old v2 task cards (importData, importBidSpirit, lotBidSpiritOld) with v3 queue-based tasks. "Sync Active Auctions" and "Sync Archived Auctions" now enqueue jobs via the queue system. Maintenance tasks (Clean Draft/Trash Lots, Clean Orphaned Meta) remain as direct-execution tasks.
- How It Works guide rewritten — Complete rewrite of the admin guide for v3 architecture. Documents webhook-first flow, all 5 job types, queue system mechanics, cron setup (external + WP-Cron), configuration constants, and troubleshooting.
Fixes
- Dual-write removed — Removed legacy handlers from
auctionCatalogUpdated(),auctionDayEnded(), anditemsUpdated()webhook methods. The old handlers were racing with the v3 worker, creating orphaned staging rows inimport_historythat were never processed. All three methods now exclusively use the v3 enqueue → spawn path. - ITEMS_UPDATED webhook — Fixed
itemsUpdated()failing to enqueue jobs. TheITEMS_UPDATEDpayload hasauctionIdnested initemsByLanguage.{lang}[0].item.auctionId, not at the top level. Added extraction logic to resolve it. - ItemUpdateWorker incomplete —
ItemUpdateWorker::process()was only callingLot::bulkSave()(staging table) without runningInsertLotsBSto process staged data into WP posts andbp_meta_data. Added the InsertLotsBS processing step with autocommit restore. Item updates now flow: stage → InsertLotsBS → WP post + meta → cache clear. - Worker spawn reliability — Changed
SyncQueue::spawnWorker()from non-blocking HTTPS to blocking HTTP loopback (http://127.0.0.1with explicitHostheader, 2s timeout). Fixes nginx 403/404 errors when HTTPS loopback hits the default vhost instead of the site's vhost. - API token constant — Plugin expects
AUCTIONFORGE_API_TOKENinwp-config.php(renamed fromUCO_API_TOKENduring the plugin rename). Documented in readme.
Database
- DB version: 22 → 23
Files Changed
- Modified:
inc/controllers/AuctionsAPI.php,inc/sync/ItemUpdateWorker.php,inc/sync/SyncQueue.php,auctionforge.php,admin/view/sync-status.php,readme.txt
---
[3.0.0] — 2025-03-14
New Feature: Webhook-First Sync Architecture (Sync v3)
Overview: Complete redesign of the BidSpirit data synchronisation pipeline. Replaces the old two-phase polling system (importBidSpirit every hour + importData every minute) with a webhook-driven job queue that processes data in near real-time.
Architecture
- 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: webhook → queue → background worker → WordPress posts. - Dual-write mode — During transition, webhooks enqueue jobs AND still run the legacy handlers. Once verified, legacy handlers can be removed cleanly.
- Job deduplication — Prevents duplicate work by checking for existing pending/processing jobs with the same auction_id + job_type.
New Components
- Job Queue System (
inc/sync/SyncQueue.php) — Priority-based FIFO queue with atomic job claiming, status tracking (pending/processing/completed/failed/skipped), worker PID tracking, and automatic stuck job recovery. - Sync Logger (
inc/sync/SyncLogger.php) — Real-time log table for admin console polling with level filtering (info/success/warning/error) and incremental cursor-based retrieval. - Catalog Sync Worker (
inc/sync/CatalogSyncWorker.php) — Processes catalog_sync, full_sync, and day_ended jobs by reusing existingLotList::singleRun()logic. - Item Update Worker (
inc/sync/ItemUpdateWorker.php) — Processes individual item_update jobs with the same logic as the webhookitemsUpdatedhandler. - Background Worker (
crontasks/syncWorker.php) — Async CLI process spawned by webhooks viaexec()or by the safety cron. Claims and processes queued jobs with a configurable timeout (default 240s). - Safety Net (
crontasks/syncSafety.php) — Hourly cron that resets stuck jobs (>10min), spawns workers for pending jobs, runs a 24-hour health check (auto-enqueues full sync if no webhooks received), and purges old data.
Admin UI
- Queue Status Dashboard — New card on Sync Status page showing pending/processing/completed/failed/skipped counts, recent jobs table with real-time refresh, worker status badge, and action buttons:
- Full Sync — Enqueues catalog sync for all active auctions
- Sync Selected — Enqueue a single auction from dropdown
- Spawn Worker — Manually trigger a background worker process
- Live Console — Dark-themed terminal console on the Sync Status page. Polls
af_sync_logevery 1.5s showing timestamped, color-coded log entries from webhooks, workers, queue operations, and the safety cron. Supports pause, clear, and auto-scroll.
Cron Changes
- Removed
importData(ran every minute — ~1,440 PHP executions/day) - Removed
importBidSpirit(ran hourly — ~24 PHP executions/day) - Added
syncSafety(runs hourly at :10 — 24 PHP executions/day) - Net effect: ~62 PHP executions/hour → 1 PHP execution/hour
- WP-Cron safety hook (
auctionforge_sync_safety) — Always-active hourly event, independent of external cron - setup.sh v3 — Updated task definitions, new
migratecommand for interactive v2→v3 transition
Database
- New table:
af_sync_queue— Job queue with status, priority, source, attempts, worker PID, timing columns - New table:
af_sync_log— Real-time log entries with context, level, auction_id, job_id - DB version: 20 → 22
Constants Added
| Constant | Default | Description |
|---|---|---|
|
AUCTIONFORGE_SYNC_WORKER_TIMEOUT| 240 | Worker process timeout in seconds ||
AUCTIONFORGE_SYNC_STALE_JOB| 600 | Seconds before a processing job is considered stuck ||
AUCTIONFORGE_SYNC_HEALTH_CHECK| 86400 | Seconds without webhook before triggering full sync ||
AUCTIONFORGE_SYNC_LOG_RETENTION| 7 | Days to keep log entries ||
AUCTIONFORGE_SYNC_QUEUE_RETENTION| 30 | Days to keep completed queue jobs ||
AUCTIONFORGE_CURL_TIMEOUT| 30 | BidSpirit API cURL timeout in seconds ||
AUCTIONFORGE_PHP_BINARY| /www/server/php/83/bin/php | PHP CLI binary path for spawning workers |AJAX Handlers Added
auctionforge_sync_log_poll— Incremental log polling for live consoleauctionforge_sync_queue_status— Queue counts + recent jobs for dashboardauctionforge_sync_enqueue— Admin-triggered sync actions (full_sync, sync_auction, spawn_worker)
Fixes
- cURL timeout — BidSpiritRequest now enforces a 30-second timeout (was unlimited/0), preventing hung connections from blocking the sync pipeline.
Files Changed
- Modified:
auctionforge.php,inc/coreIncludes.php,inc/controllers/AuctionsAPI.php,inc/BidSpiritRequest.php,admin/view/sync-status.php,crontasks/setup.sh - Created:
inc/sync/SyncQueue.php,inc/sync/SyncLogger.php,inc/sync/CatalogSyncWorker.php,inc/sync/ItemUpdateWorker.php,crontasks/syncWorker.php,crontasks/syncSafety.php
---
[2.7.3.0]
Fixes
- Various stability improvements and bug fixes.
[2.7.1.2]
Fixes
- Added missing
vatAndCommission()function inloadBid()— the sales tax display on single lot pages was never being rendered because the code to callloadTemplateforvat-and-commission-templatewas missing fromapp.js.
[2.7.1.1]
Fixes
- 2 decimal places now only appear in the bid modal (Your max bid, Total Price) via
showDecimalsflag. 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.
[2.7.0.9]
Fixes
- Fixed fatal error during plugin install/upgrade:
class-stats-database.phprequire failure.
[2.7.0.0]
New Features: Advanced Lot Analytics
- Conversion Tracking, Peak Viewing Times, Pre-Sale vs Live Comparison, Category Performance, Share Analytics, Search → View Funnel, Click-Through Tracking, CSV Export, Hot Lot Badge.
- New DB table:
af_lot_shares. New columns onaf_lot_analytics. DB version bumped to 20.
[2.6.0.0]
New Feature: Lot Analytics
- Comprehensive lot view and favorite tracking system with admin dashboard.
[2.5.0.0]
New Features
- Site Statistics System — Full website analytics built into the plugin admin.
- Recently Viewed Items — Profile page tab showing last 20 viewed lots per user.
- Namespace resolution — Fixed fatal error in
-
v3.6.0.17 Stable Apr 23, 2026Download v3.6.0.17📦 8.94 MB⚙️ WP 5.2+🔧 PHP 7.2+✓ Tested 6.4
AuctionForge Changelog
All notable changes to the AuctionForge plugin are documented in this file.
---
[3.6.0.7] — 2026-04-14
Hotfix
Fixes
- Namespace resolution — Fixed fatal error in
wp_footercommission label hook caused by unqualifiedSettingsHelperandSettingsclass references. Now uses fully qualified namespaces.
Files Changed
- Modified:
auctionforge.php
---
[3.6.0.6] — 2026-04-14
Commission Label Override Fix
Fixes
- Theme template override compatibility — Moved the commission label JS override from the
single-lot.phptemplate intoauctionforge.phpviawp_footerhook (priority 99). Sites with theme-level template overrides (e.g.themes/*/auctionforge/single-lot.php) were not picking up the inline script. Thewp_footerapproach works universally on all single lot pages.
Files Changed
- Modified:
auctionforge.php,templates/single-lot.php
---
[3.6.0.5] — 2026-04-14
Commission Label Override
Features
- Commission Label Setting — New dropdown in Settings → Appearance allowing admins to choose between "Buyer's Premium" (default) and "Auction House Commission" as the label displayed on lot pages. This overrides the Bidspirit JS client's default label using a MutationObserver that catches asynchronously injected text.
Files Changed
- Modified:
inc/controllers/Settings.php,templates/single-lot.php
---
[3.6.0.4] — 2026-04-12
Auction Approval Modal Redesign
Changes
- Removed BidSpirit Terms of Use — The generic BidSpirit "Terms of Use" section that appeared at the top of the non-credit-card approval modal has been removed. The modal now shows only the auction house's own legal agreements managed within the plugin.
- Renamed Modal Title — Changed "Terms of conditions" to "Terms & Conditions".
- Larger Scroll Area — The Terms & Conditions scroll box is now 350px tall (up from 200px) for easier reading.
- Proportional Section Heights — Refund & Return Policy and Chargeback Waiver sections use a shorter 260px scroll box to visually distinguish them from the primary Terms & Conditions.
Files Changed
- Modified:
templates/js-chunks/approval-info.php,assets/js/app.js
---
[3.6.0.2] — 2026-04-10
Webhook Token Generator
Features
- Token Generator Widget — Added a 16-character random token generator directly below the "Webhook auth token" field on the Settings page. Includes a "Generate Token" button and a clipboard copy icon with visual feedback.
Files Changed
- Modified:
inc/controllers/Settings.php
---
[3.6.0.1] — 2026-04-10
Patch
Changes
- Version bump.
---
[3.6.0.0] — 2026-04-10
Legal Agreements for Auction Approval
Features
- Terms & Conditions — A mandatory, scrollable Terms & Conditions document is now displayed during the auction approval process. Bidders must scroll to the bottom and check an agreement box before their approval request is submitted. Always enabled.
- Refund & Return Policy — An optional, scrollable Refund & Return Policy can be enabled in Settings. When enabled, bidders must read and accept it during auction approval.
- Chargeback Waiver — An optional, scrollable Chargeback Waiver can be enabled in Settings. When enabled, bidders must read and accept it during auction approval.
- Admin Management — New "Legal Agreements" page under the Bidspirit admin menu with tabbed TinyMCE editors for each agreement type. Includes automatic version numbering (incremented on content change) and full version history.
- Consent Logging — Every agreement acceptance is logged to a dedicated database table (
af_user_agreement_log) with the agreement type, version, user email, IP address, user agent, auction ID, and timestamp. - User Tracking Integration — Agreement events (
terms_agreement,refund_agreement,chargeback_waiver) are also recorded in the existing IP tracking system alongside registration, login, and bid events. - Placeholder Content — Default sample content is seeded on plugin activation for all three agreement types.
Settings Added
- Enable Refund & Return Policy — Toggle to require bidders to accept the refund policy during auction approval.
- Enable Chargeback Waiver — Toggle to require bidders to accept the chargeback waiver during auction approval.
Database
- New table:
af_legal_agreements— Current active agreement content per type - New table:
af_legal_agreement_versions— Version history archive - New table:
af_user_agreement_log— User consent records
Files Changed
- Modified:
auctionforge.php,inc/controllers/Settings.php,inc/controllers/BidspiritViews.php,inc/ip-logger.php,templates/js-chunks/approval-info.php,assets/js/app.js - Created:
inc/legal/class-legal-agreements.php,admin/view/legal-agreements.php
---
[3.5.0.6] — 2026-04-08
Bid Event Tracking
Features
- Bid Tracking — All successful bids (regular, catalog, pre-sale buyout, post-sale purchase) now fire
afLogIP("bid", bidspiritUser)to capture the bidder's full identity in the user tracking table. - Whitelist Update — Added
bidto the allowedevent_typevalues in both the local plugin and the central WPDeploy API.
---
[3.5.0.5] — 2026-04-08
Self-Healing Database Schema
Features
- Auto-Migration — The plugin now auto-detects and adds any missing tracking table columns on version upgrade, ensuring sites with older schemas seamlessly migrate without manual SQL.
---
[3.5.0.4] — 2026-04-08
API Key Auto-Healing
Features
- Seamless Self-Registration — The WordPress plugin now autonomously regenerates and saves a fresh API Key whenever WPDeploy rejects a payload with an
api_key_collisionerror. This guarantees zero-downtime security handovers when developers clone instances to proxy/staging servers.
---
[3.5.0.3] — 2026-04-08
API Key Collision Defense
Features
- 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_collisionerrors, directly instructing developers to update cloned keys.
---
[3.5.0.2] — 2026-04-08
Modal Trigger Hotfix
Fixes
- Restructured internal UI rendering priority to gracefully deploy the inline Modal triggers inside custom IP log view without colliding with cached
z-indexstacks.
---
[3.5.0.1] — 2026-04-08
Hotfix
Fixes
- Timed Auction Badge Visibility — Fixed a strict type-matching bug in the main
auction_list.phpcore file that incorrectly hid the "Timed Auction" badge overlay from valid timed/online auctions on the main upcoming/archive views. The badge now displays properly across all manual and Bidspirit-synced objects when toggled on.
Files Changed
- Modified:
templates/main/auction_list.php
---
[3.2.9.1] — 2026-03-30
Timed Auction Display Enhancements
Features
- Timed Auction Countdown Text Toggle — Added a WP-Admin setting "Change text to 'Auction will close in'" that conditionally changes the countdown label for timed/online auctions on single lot pages.
- Shortcode Text Toggle Support — Extended the new countdown text logic to the
bp_upcoming_wideshortcodes so "Live bidding starts in:" successfully transitions to "Auction will close in:" for timed auctions.
Files Changed
- Modified:
inc/controllers/Settings.php,templates/single-lot.php,templates/shortcodes/upcoming-auction-wide.php,templates/shortcodes/upcoming-auction-wide-manual.php
---
[3.2.9.0] — 2026-03-29
Billing & Invoices Polish
Fixes
- Profile Invoice ID Tracking — Prevented internal auction codes (e.g.
002orai4) from breaking into the clean hyphenated titles inside theprofile-templates.phpview. - Dynamic Payment Statuses — Replaced Bidspirit's default/cached
NOT PAIDHTML payloads by wiring thedompdfgenerator to directly respect the current$b.statusstring from the API (resolving instances where a paid invoice still printed "NOT PAID" atop the document). - Payment Instructions Conditional — Automatically hide the "Payment Instructions" block from the PDF footer when an invoice is fully paid.
- Improved Nomenclature — Changed "Invoice No:" to "Bidder No:" on document output to prevent confusion with static invoice ledger IDs.
---
[3.2.6.0] — 2026-03-28
Multi-Day Auction Lot Filtering Fix
Fixes
- Day 2+ showing lots from Day 1 in multi-day auctions — The
itemIndexcolumn inbp_meta_dataisvarchar(55), but the day-range filter inBidspiritQuery::bp_query_where()was comparing it as a string. With string comparison, lot numbers like'11','101'–'145'incorrectly fell between'1001'and'1450', causing Day 1 lots to leak into Day 2 results. Fixed by usingCAST(bpMeta.itemIndex AS UNSIGNED)for numeric comparison andintval()on the PHP-side boundary values. Letter lots (e.g.14A,1025A) are handled correctly —CASTstrips the suffix, keeping them grouped with their base lot number.
Files Changed
- Modified:
inc/controllers/BidspiritQuery.php
---
[3.2.5.9] — 2026-03-27
Catalog Page Fix
Fixes
- Duplicate preview hours on catalog pages — The
displayHoursfield was rendered twice: once via thebp_after_description_auctionhook inBidspiritViews.phpand once inline in the auction template. Removed the hook-based rendering to eliminate the duplication.
Files Changed
- Modified:
inc/controllers/BidspiritViews.php,templates/main/auction.php
---
[3.2.5] — 2026-03-19
Sync Reliability & Stuck Lot Prevention
Fixes
- CATALOG_PUBLISHED webhook now triggers catalog sync — Previously only sent push notifications without syncing lots. When the earlier AUCTION_CATALOG_UPDATED fired before the catalog was ready on BidSpirit, lots were never imported. CATALOG_PUBLISHED now calls
auctionCatalogUpdated()to trigger a full catalog sync when the catalog is actually available. - 0-lot API results now fail instead of silently succeeding — When BidSpirit API returns 0 lots (catalog not yet ready), the sync job now fails with an explicit error message, allowing the next webhook to create a fresh retry job.
- Expanded CDN allowlist in pre_http_request filter — The HTTP filter during bulk post insertion now allows all
*.bidspirit.comsubdomains and BidSpirit image CDNs (fastly.net,cloudfront.net). Previously onlybidspirit.comandwww.bidspirit.comwere allowed, blocking image downloads during sync and causing worker hangs. - InsertLotsBS timeout guard — Stage 5 (InsertLotsBS processing loop) now has a 180-second timeout and logs progress every 2 batches. Prevents indefinite hangs that previously required manual force-kill.
- fixResult() no longer marks lots as done when postId=0 — When
lotProcessing()fails to create a WP post, the staging row now keepssyncFinished=0so the lot is retried on the next sync pass, instead of being permanently marked as complete with no actual post. - lotProcessing() logs error on missing auction term — Previously returned 0 silently when
Auction::findAuctionById()failed. Now logs an explicit error that feeds intofixResult()to keep the lot retryable. - Hourly orphan detection in safety cron — New step in
syncSafety.phpdetects lot posts that exist inbp_meta_databut are missing their auction taxonomy assignment (caused by workers killed mid-batch) and auto-repairs them withwp_set_object_terms().
Files Changed
- Modified:
inc/controllers/AuctionsAPI.php,inc/sync/CatalogSyncWorker.php,inc/abs/InsertLotsAbstract.php,inc/import/InsertLotsBS.php,crontasks/syncSafety.php
---
[3.2.4] — 2026-03-18
Sync Worker Hang Fix
Fixes
- Sync workers hanging at InsertLotsBS stage — Third-party plugins (Smush Pro, SmartCrawl SEO, WPMU DEV Updates) hook into
wp_insert_post()and make blocking outbound HTTPS calls for every lot processed. With 489+ lots per auction, this caused workers to hang indefinitely on socket reads to WPMU DEV servers (32.193.94.25,32.193.93.106). AddedWP_IMPORTINGconstant at the REST worker entry point and apre_http_requestfilter inCatalogSyncWorkerthat blocks all non-essential external HTTP during the batch post-insertion phase. Loopback (127.0.0.1,localhost) and BidSpirit API calls remain allowed. - Stuck staging rows after force-kill — When workers were force-killed mid-sync, staging rows in
import_historywere left withsyncstart=1and never unblocked. Subsequent sync runs could not see these rows (filtered out byLot::getRawLots()), causing the InsertLotsBS loop to exit immediately with 0 posts processed. Combined with job deduplication (SyncQueue::enqueue()skips if aprocessingjob exists), this created a deadlock where no new sync could proceed.
Files Changed
- Modified:
auctionforge.php,inc/sync/CatalogSyncWorker.php
---
[3.2.2] — 2026-03-17
Full Sync Auction Discovery Fix
Fixes
- Full Sync finds no auctions on fresh sites — The v3
full_syncaction only queried the WordPress database for existing auction terms, but on a freshly deployed site the database has zero auctions. AddedAuctionList::init()discovery step before querying the DB, so Full Sync now fetches all auctions from the BidSpirit API and creates taxonomy terms first, then enqueues catalog sync jobs for each.
Files Changed
- Modified:
auctionforge.php
---
[3.2.0] — 2026-03-14
Webhook Pipeline Fixes, Archive Sync & Admin UI Overhaul
New Features
- Archive Sync — New "Archive Sync" button on Sync Status admin page. Enqueues catalog sync jobs for all ARCHIVED/ENDED auctions. Past auctions now appear in the auction dropdown with an optgroup separator and state label.
- Sync Tasks v3 — Replaced old v2 task cards (importData, importBidSpirit, lotBidSpiritOld) with v3 queue-based tasks. "Sync Active Auctions" and "Sync Archived Auctions" now enqueue jobs via the queue system. Maintenance tasks (Clean Draft/Trash Lots, Clean Orphaned Meta) remain as direct-execution tasks.
- How It Works guide rewritten — Complete rewrite of the admin guide for v3 architecture. Documents webhook-first flow, all 5 job types, queue system mechanics, cron setup (external + WP-Cron), configuration constants, and troubleshooting.
Fixes
- Dual-write removed — Removed legacy handlers from
auctionCatalogUpdated(),auctionDayEnded(), anditemsUpdated()webhook methods. The old handlers were racing with the v3 worker, creating orphaned staging rows inimport_historythat were never processed. All three methods now exclusively use the v3 enqueue → spawn path. - ITEMS_UPDATED webhook — Fixed
itemsUpdated()failing to enqueue jobs. TheITEMS_UPDATEDpayload hasauctionIdnested initemsByLanguage.{lang}[0].item.auctionId, not at the top level. Added extraction logic to resolve it. - ItemUpdateWorker incomplete —
ItemUpdateWorker::process()was only callingLot::bulkSave()(staging table) without runningInsertLotsBSto process staged data into WP posts andbp_meta_data. Added the InsertLotsBS processing step with autocommit restore. Item updates now flow: stage → InsertLotsBS → WP post + meta → cache clear. - Worker spawn reliability — Changed
SyncQueue::spawnWorker()from non-blocking HTTPS to blocking HTTP loopback (http://127.0.0.1with explicitHostheader, 2s timeout). Fixes nginx 403/404 errors when HTTPS loopback hits the default vhost instead of the site's vhost. - API token constant — Plugin expects
AUCTIONFORGE_API_TOKENinwp-config.php(renamed fromUCO_API_TOKENduring the plugin rename). Documented in readme.
Database
- DB version: 22 → 23
Files Changed
- Modified:
inc/controllers/AuctionsAPI.php,inc/sync/ItemUpdateWorker.php,inc/sync/SyncQueue.php,auctionforge.php,admin/view/sync-status.php,readme.txt
---
[3.0.0] — 2025-03-14
New Feature: Webhook-First Sync Architecture (Sync v3)
Overview: Complete redesign of the BidSpirit data synchronisation pipeline. Replaces the old two-phase polling system (importBidSpirit every hour + importData every minute) with a webhook-driven job queue that processes data in near real-time.
Architecture
- 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: webhook → queue → background worker → WordPress posts. - Dual-write mode — During transition, webhooks enqueue jobs AND still run the legacy handlers. Once verified, legacy handlers can be removed cleanly.
- Job deduplication — Prevents duplicate work by checking for existing pending/processing jobs with the same auction_id + job_type.
New Components
- Job Queue System (
inc/sync/SyncQueue.php) — Priority-based FIFO queue with atomic job claiming, status tracking (pending/processing/completed/failed/skipped), worker PID tracking, and automatic stuck job recovery. - Sync Logger (
inc/sync/SyncLogger.php) — Real-time log table for admin console polling with level filtering (info/success/warning/error) and incremental cursor-based retrieval. - Catalog Sync Worker (
inc/sync/CatalogSyncWorker.php) — Processes catalog_sync, full_sync, and day_ended jobs by reusing existingLotList::singleRun()logic. - Item Update Worker (
inc/sync/ItemUpdateWorker.php) — Processes individual item_update jobs with the same logic as the webhookitemsUpdatedhandler. - Background Worker (
crontasks/syncWorker.php) — Async CLI process spawned by webhooks viaexec()or by the safety cron. Claims and processes queued jobs with a configurable timeout (default 240s). - Safety Net (
crontasks/syncSafety.php) — Hourly cron that resets stuck jobs (>10min), spawns workers for pending jobs, runs a 24-hour health check (auto-enqueues full sync if no webhooks received), and purges old data.
Admin UI
- Queue Status Dashboard — New card on Sync Status page showing pending/processing/completed/failed/skipped counts, recent jobs table with real-time refresh, worker status badge, and action buttons:
- Full Sync — Enqueues catalog sync for all active auctions
- Sync Selected — Enqueue a single auction from dropdown
- Spawn Worker — Manually trigger a background worker process
- Live Console — Dark-themed terminal console on the Sync Status page. Polls
af_sync_logevery 1.5s showing timestamped, color-coded log entries from webhooks, workers, queue operations, and the safety cron. Supports pause, clear, and auto-scroll.
Cron Changes
- Removed
importData(ran every minute — ~1,440 PHP executions/day) - Removed
importBidSpirit(ran hourly — ~24 PHP executions/day) - Added
syncSafety(runs hourly at :10 — 24 PHP executions/day) - Net effect: ~62 PHP executions/hour → 1 PHP execution/hour
- WP-Cron safety hook (
auctionforge_sync_safety) — Always-active hourly event, independent of external cron - setup.sh v3 — Updated task definitions, new
migratecommand for interactive v2→v3 transition
Database
- New table:
af_sync_queue— Job queue with status, priority, source, attempts, worker PID, timing columns - New table:
af_sync_log— Real-time log entries with context, level, auction_id, job_id - DB version: 20 → 22
Constants Added
| Constant | Default | Description |
|---|---|---|
|
AUCTIONFORGE_SYNC_WORKER_TIMEOUT| 240 | Worker process timeout in seconds ||
AUCTIONFORGE_SYNC_STALE_JOB| 600 | Seconds before a processing job is considered stuck ||
AUCTIONFORGE_SYNC_HEALTH_CHECK| 86400 | Seconds without webhook before triggering full sync ||
AUCTIONFORGE_SYNC_LOG_RETENTION| 7 | Days to keep log entries ||
AUCTIONFORGE_SYNC_QUEUE_RETENTION| 30 | Days to keep completed queue jobs ||
AUCTIONFORGE_CURL_TIMEOUT| 30 | BidSpirit API cURL timeout in seconds ||
AUCTIONFORGE_PHP_BINARY| /www/server/php/83/bin/php | PHP CLI binary path for spawning workers |AJAX Handlers Added
auctionforge_sync_log_poll— Incremental log polling for live consoleauctionforge_sync_queue_status— Queue counts + recent jobs for dashboardauctionforge_sync_enqueue— Admin-triggered sync actions (full_sync, sync_auction, spawn_worker)
Fixes
- cURL timeout — BidSpiritRequest now enforces a 30-second timeout (was unlimited/0), preventing hung connections from blocking the sync pipeline.
Files Changed
- Modified:
auctionforge.php,inc/coreIncludes.php,inc/controllers/AuctionsAPI.php,inc/BidSpiritRequest.php,admin/view/sync-status.php,crontasks/setup.sh - Created:
inc/sync/SyncQueue.php,inc/sync/SyncLogger.php,inc/sync/CatalogSyncWorker.php,inc/sync/ItemUpdateWorker.php,crontasks/syncWorker.php,crontasks/syncSafety.php
---
[2.7.3.0]
Fixes
- Various stability improvements and bug fixes.
[2.7.1.2]
Fixes
- Added missing
vatAndCommission()function inloadBid()— the sales tax display on single lot pages was never being rendered because the code to callloadTemplateforvat-and-commission-templatewas missing fromapp.js.
[2.7.1.1]
Fixes
- 2 decimal places now only appear in the bid modal (Your max bid, Total Price) via
showDecimalsflag. 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.
[2.7.0.9]
Fixes
- Fixed fatal error during plugin install/upgrade:
class-stats-database.phprequire failure.
[2.7.0.0]
New Features: Advanced Lot Analytics
- Conversion Tracking, Peak Viewing Times, Pre-Sale vs Live Comparison, Category Performance, Share Analytics, Search → View Funnel, Click-Through Tracking, CSV Export, Hot Lot Badge.
- New DB table:
af_lot_shares. New columns onaf_lot_analytics. DB version bumped to 20.
[2.6.0.0]
New Feature: Lot Analytics
- Comprehensive lot view and favorite tracking system with admin dashboard.
[2.5.0.0]
New Features
- Site Statistics System — Full website analytics built into the plugin admin.
- Recently Viewed Items — Profile page tab showing last 20 viewed lots per user.
- Namespace resolution — Fixed fatal error in
-
v3.6.0.16 Stable Apr 21, 2026Download v3.6.0.16📦 8.94 MB⚙️ WP 5.2+🔧 PHP 7.2+✓ Tested 6.4
AuctionForge Changelog
All notable changes to the AuctionForge plugin are documented in this file.
---
[3.6.0.7] — 2026-04-14
Hotfix
Fixes
- Namespace resolution — Fixed fatal error in
wp_footercommission label hook caused by unqualifiedSettingsHelperandSettingsclass references. Now uses fully qualified namespaces.
Files Changed
- Modified:
auctionforge.php
---
[3.6.0.6] — 2026-04-14
Commission Label Override Fix
Fixes
- Theme template override compatibility — Moved the commission label JS override from the
single-lot.phptemplate intoauctionforge.phpviawp_footerhook (priority 99). Sites with theme-level template overrides (e.g.themes/*/auctionforge/single-lot.php) were not picking up the inline script. Thewp_footerapproach works universally on all single lot pages.
Files Changed
- Modified:
auctionforge.php,templates/single-lot.php
---
[3.6.0.5] — 2026-04-14
Commission Label Override
Features
- Commission Label Setting — New dropdown in Settings → Appearance allowing admins to choose between "Buyer's Premium" (default) and "Auction House Commission" as the label displayed on lot pages. This overrides the Bidspirit JS client's default label using a MutationObserver that catches asynchronously injected text.
Files Changed
- Modified:
inc/controllers/Settings.php,templates/single-lot.php
---
[3.6.0.4] — 2026-04-12
Auction Approval Modal Redesign
Changes
- Removed BidSpirit Terms of Use — The generic BidSpirit "Terms of Use" section that appeared at the top of the non-credit-card approval modal has been removed. The modal now shows only the auction house's own legal agreements managed within the plugin.
- Renamed Modal Title — Changed "Terms of conditions" to "Terms & Conditions".
- Larger Scroll Area — The Terms & Conditions scroll box is now 350px tall (up from 200px) for easier reading.
- Proportional Section Heights — Refund & Return Policy and Chargeback Waiver sections use a shorter 260px scroll box to visually distinguish them from the primary Terms & Conditions.
Files Changed
- Modified:
templates/js-chunks/approval-info.php,assets/js/app.js
---
[3.6.0.2] — 2026-04-10
Webhook Token Generator
Features
- Token Generator Widget — Added a 16-character random token generator directly below the "Webhook auth token" field on the Settings page. Includes a "Generate Token" button and a clipboard copy icon with visual feedback.
Files Changed
- Modified:
inc/controllers/Settings.php
---
[3.6.0.1] — 2026-04-10
Patch
Changes
- Version bump.
---
[3.6.0.0] — 2026-04-10
Legal Agreements for Auction Approval
Features
- Terms & Conditions — A mandatory, scrollable Terms & Conditions document is now displayed during the auction approval process. Bidders must scroll to the bottom and check an agreement box before their approval request is submitted. Always enabled.
- Refund & Return Policy — An optional, scrollable Refund & Return Policy can be enabled in Settings. When enabled, bidders must read and accept it during auction approval.
- Chargeback Waiver — An optional, scrollable Chargeback Waiver can be enabled in Settings. When enabled, bidders must read and accept it during auction approval.
- Admin Management — New "Legal Agreements" page under the Bidspirit admin menu with tabbed TinyMCE editors for each agreement type. Includes automatic version numbering (incremented on content change) and full version history.
- Consent Logging — Every agreement acceptance is logged to a dedicated database table (
af_user_agreement_log) with the agreement type, version, user email, IP address, user agent, auction ID, and timestamp. - User Tracking Integration — Agreement events (
terms_agreement,refund_agreement,chargeback_waiver) are also recorded in the existing IP tracking system alongside registration, login, and bid events. - Placeholder Content — Default sample content is seeded on plugin activation for all three agreement types.
Settings Added
- Enable Refund & Return Policy — Toggle to require bidders to accept the refund policy during auction approval.
- Enable Chargeback Waiver — Toggle to require bidders to accept the chargeback waiver during auction approval.
Database
- New table:
af_legal_agreements— Current active agreement content per type - New table:
af_legal_agreement_versions— Version history archive - New table:
af_user_agreement_log— User consent records
Files Changed
- Modified:
auctionforge.php,inc/controllers/Settings.php,inc/controllers/BidspiritViews.php,inc/ip-logger.php,templates/js-chunks/approval-info.php,assets/js/app.js - Created:
inc/legal/class-legal-agreements.php,admin/view/legal-agreements.php
---
[3.5.0.6] — 2026-04-08
Bid Event Tracking
Features
- Bid Tracking — All successful bids (regular, catalog, pre-sale buyout, post-sale purchase) now fire
afLogIP("bid", bidspiritUser)to capture the bidder's full identity in the user tracking table. - Whitelist Update — Added
bidto the allowedevent_typevalues in both the local plugin and the central WPDeploy API.
---
[3.5.0.5] — 2026-04-08
Self-Healing Database Schema
Features
- Auto-Migration — The plugin now auto-detects and adds any missing tracking table columns on version upgrade, ensuring sites with older schemas seamlessly migrate without manual SQL.
---
[3.5.0.4] — 2026-04-08
API Key Auto-Healing
Features
- Seamless Self-Registration — The WordPress plugin now autonomously regenerates and saves a fresh API Key whenever WPDeploy rejects a payload with an
api_key_collisionerror. This guarantees zero-downtime security handovers when developers clone instances to proxy/staging servers.
---
[3.5.0.3] — 2026-04-08
API Key Collision Defense
Features
- 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_collisionerrors, directly instructing developers to update cloned keys.
---
[3.5.0.2] — 2026-04-08
Modal Trigger Hotfix
Fixes
- Restructured internal UI rendering priority to gracefully deploy the inline Modal triggers inside custom IP log view without colliding with cached
z-indexstacks.
---
[3.5.0.1] — 2026-04-08
Hotfix
Fixes
- Timed Auction Badge Visibility — Fixed a strict type-matching bug in the main
auction_list.phpcore file that incorrectly hid the "Timed Auction" badge overlay from valid timed/online auctions on the main upcoming/archive views. The badge now displays properly across all manual and Bidspirit-synced objects when toggled on.
Files Changed
- Modified:
templates/main/auction_list.php
---
[3.2.9.1] — 2026-03-30
Timed Auction Display Enhancements
Features
- Timed Auction Countdown Text Toggle — Added a WP-Admin setting "Change text to 'Auction will close in'" that conditionally changes the countdown label for timed/online auctions on single lot pages.
- Shortcode Text Toggle Support — Extended the new countdown text logic to the
bp_upcoming_wideshortcodes so "Live bidding starts in:" successfully transitions to "Auction will close in:" for timed auctions.
Files Changed
- Modified:
inc/controllers/Settings.php,templates/single-lot.php,templates/shortcodes/upcoming-auction-wide.php,templates/shortcodes/upcoming-auction-wide-manual.php
---
[3.2.9.0] — 2026-03-29
Billing & Invoices Polish
Fixes
- Profile Invoice ID Tracking — Prevented internal auction codes (e.g.
002orai4) from breaking into the clean hyphenated titles inside theprofile-templates.phpview. - Dynamic Payment Statuses — Replaced Bidspirit's default/cached
NOT PAIDHTML payloads by wiring thedompdfgenerator to directly respect the current$b.statusstring from the API (resolving instances where a paid invoice still printed "NOT PAID" atop the document). - Payment Instructions Conditional — Automatically hide the "Payment Instructions" block from the PDF footer when an invoice is fully paid.
- Improved Nomenclature — Changed "Invoice No:" to "Bidder No:" on document output to prevent confusion with static invoice ledger IDs.
---
[3.2.6.0] — 2026-03-28
Multi-Day Auction Lot Filtering Fix
Fixes
- Day 2+ showing lots from Day 1 in multi-day auctions — The
itemIndexcolumn inbp_meta_dataisvarchar(55), but the day-range filter inBidspiritQuery::bp_query_where()was comparing it as a string. With string comparison, lot numbers like'11','101'–'145'incorrectly fell between'1001'and'1450', causing Day 1 lots to leak into Day 2 results. Fixed by usingCAST(bpMeta.itemIndex AS UNSIGNED)for numeric comparison andintval()on the PHP-side boundary values. Letter lots (e.g.14A,1025A) are handled correctly —CASTstrips the suffix, keeping them grouped with their base lot number.
Files Changed
- Modified:
inc/controllers/BidspiritQuery.php
---
[3.2.5.9] — 2026-03-27
Catalog Page Fix
Fixes
- Duplicate preview hours on catalog pages — The
displayHoursfield was rendered twice: once via thebp_after_description_auctionhook inBidspiritViews.phpand once inline in the auction template. Removed the hook-based rendering to eliminate the duplication.
Files Changed
- Modified:
inc/controllers/BidspiritViews.php,templates/main/auction.php
---
[3.2.5] — 2026-03-19
Sync Reliability & Stuck Lot Prevention
Fixes
- CATALOG_PUBLISHED webhook now triggers catalog sync — Previously only sent push notifications without syncing lots. When the earlier AUCTION_CATALOG_UPDATED fired before the catalog was ready on BidSpirit, lots were never imported. CATALOG_PUBLISHED now calls
auctionCatalogUpdated()to trigger a full catalog sync when the catalog is actually available. - 0-lot API results now fail instead of silently succeeding — When BidSpirit API returns 0 lots (catalog not yet ready), the sync job now fails with an explicit error message, allowing the next webhook to create a fresh retry job.
- Expanded CDN allowlist in pre_http_request filter — The HTTP filter during bulk post insertion now allows all
*.bidspirit.comsubdomains and BidSpirit image CDNs (fastly.net,cloudfront.net). Previously onlybidspirit.comandwww.bidspirit.comwere allowed, blocking image downloads during sync and causing worker hangs. - InsertLotsBS timeout guard — Stage 5 (InsertLotsBS processing loop) now has a 180-second timeout and logs progress every 2 batches. Prevents indefinite hangs that previously required manual force-kill.
- fixResult() no longer marks lots as done when postId=0 — When
lotProcessing()fails to create a WP post, the staging row now keepssyncFinished=0so the lot is retried on the next sync pass, instead of being permanently marked as complete with no actual post. - lotProcessing() logs error on missing auction term — Previously returned 0 silently when
Auction::findAuctionById()failed. Now logs an explicit error that feeds intofixResult()to keep the lot retryable. - Hourly orphan detection in safety cron — New step in
syncSafety.phpdetects lot posts that exist inbp_meta_databut are missing their auction taxonomy assignment (caused by workers killed mid-batch) and auto-repairs them withwp_set_object_terms().
Files Changed
- Modified:
inc/controllers/AuctionsAPI.php,inc/sync/CatalogSyncWorker.php,inc/abs/InsertLotsAbstract.php,inc/import/InsertLotsBS.php,crontasks/syncSafety.php
---
[3.2.4] — 2026-03-18
Sync Worker Hang Fix
Fixes
- Sync workers hanging at InsertLotsBS stage — Third-party plugins (Smush Pro, SmartCrawl SEO, WPMU DEV Updates) hook into
wp_insert_post()and make blocking outbound HTTPS calls for every lot processed. With 489+ lots per auction, this caused workers to hang indefinitely on socket reads to WPMU DEV servers (32.193.94.25,32.193.93.106). AddedWP_IMPORTINGconstant at the REST worker entry point and apre_http_requestfilter inCatalogSyncWorkerthat blocks all non-essential external HTTP during the batch post-insertion phase. Loopback (127.0.0.1,localhost) and BidSpirit API calls remain allowed. - Stuck staging rows after force-kill — When workers were force-killed mid-sync, staging rows in
import_historywere left withsyncstart=1and never unblocked. Subsequent sync runs could not see these rows (filtered out byLot::getRawLots()), causing the InsertLotsBS loop to exit immediately with 0 posts processed. Combined with job deduplication (SyncQueue::enqueue()skips if aprocessingjob exists), this created a deadlock where no new sync could proceed.
Files Changed
- Modified:
auctionforge.php,inc/sync/CatalogSyncWorker.php
---
[3.2.2] — 2026-03-17
Full Sync Auction Discovery Fix
Fixes
- Full Sync finds no auctions on fresh sites — The v3
full_syncaction only queried the WordPress database for existing auction terms, but on a freshly deployed site the database has zero auctions. AddedAuctionList::init()discovery step before querying the DB, so Full Sync now fetches all auctions from the BidSpirit API and creates taxonomy terms first, then enqueues catalog sync jobs for each.
Files Changed
- Modified:
auctionforge.php
---
[3.2.0] — 2026-03-14
Webhook Pipeline Fixes, Archive Sync & Admin UI Overhaul
New Features
- Archive Sync — New "Archive Sync" button on Sync Status admin page. Enqueues catalog sync jobs for all ARCHIVED/ENDED auctions. Past auctions now appear in the auction dropdown with an optgroup separator and state label.
- Sync Tasks v3 — Replaced old v2 task cards (importData, importBidSpirit, lotBidSpiritOld) with v3 queue-based tasks. "Sync Active Auctions" and "Sync Archived Auctions" now enqueue jobs via the queue system. Maintenance tasks (Clean Draft/Trash Lots, Clean Orphaned Meta) remain as direct-execution tasks.
- How It Works guide rewritten — Complete rewrite of the admin guide for v3 architecture. Documents webhook-first flow, all 5 job types, queue system mechanics, cron setup (external + WP-Cron), configuration constants, and troubleshooting.
Fixes
- Dual-write removed — Removed legacy handlers from
auctionCatalogUpdated(),auctionDayEnded(), anditemsUpdated()webhook methods. The old handlers were racing with the v3 worker, creating orphaned staging rows inimport_historythat were never processed. All three methods now exclusively use the v3 enqueue → spawn path. - ITEMS_UPDATED webhook — Fixed
itemsUpdated()failing to enqueue jobs. TheITEMS_UPDATEDpayload hasauctionIdnested initemsByLanguage.{lang}[0].item.auctionId, not at the top level. Added extraction logic to resolve it. - ItemUpdateWorker incomplete —
ItemUpdateWorker::process()was only callingLot::bulkSave()(staging table) without runningInsertLotsBSto process staged data into WP posts andbp_meta_data. Added the InsertLotsBS processing step with autocommit restore. Item updates now flow: stage → InsertLotsBS → WP post + meta → cache clear. - Worker spawn reliability — Changed
SyncQueue::spawnWorker()from non-blocking HTTPS to blocking HTTP loopback (http://127.0.0.1with explicitHostheader, 2s timeout). Fixes nginx 403/404 errors when HTTPS loopback hits the default vhost instead of the site's vhost. - API token constant — Plugin expects
AUCTIONFORGE_API_TOKENinwp-config.php(renamed fromUCO_API_TOKENduring the plugin rename). Documented in readme.
Database
- DB version: 22 → 23
Files Changed
- Modified:
inc/controllers/AuctionsAPI.php,inc/sync/ItemUpdateWorker.php,inc/sync/SyncQueue.php,auctionforge.php,admin/view/sync-status.php,readme.txt
---
[3.0.0] — 2025-03-14
New Feature: Webhook-First Sync Architecture (Sync v3)
Overview: Complete redesign of the BidSpirit data synchronisation pipeline. Replaces the old two-phase polling system (importBidSpirit every hour + importData every minute) with a webhook-driven job queue that processes data in near real-time.
Architecture
- 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: webhook → queue → background worker → WordPress posts. - Dual-write mode — During transition, webhooks enqueue jobs AND still run the legacy handlers. Once verified, legacy handlers can be removed cleanly.
- Job deduplication — Prevents duplicate work by checking for existing pending/processing jobs with the same auction_id + job_type.
New Components
- Job Queue System (
inc/sync/SyncQueue.php) — Priority-based FIFO queue with atomic job claiming, status tracking (pending/processing/completed/failed/skipped), worker PID tracking, and automatic stuck job recovery. - Sync Logger (
inc/sync/SyncLogger.php) — Real-time log table for admin console polling with level filtering (info/success/warning/error) and incremental cursor-based retrieval. - Catalog Sync Worker (
inc/sync/CatalogSyncWorker.php) — Processes catalog_sync, full_sync, and day_ended jobs by reusing existingLotList::singleRun()logic. - Item Update Worker (
inc/sync/ItemUpdateWorker.php) — Processes individual item_update jobs with the same logic as the webhookitemsUpdatedhandler. - Background Worker (
crontasks/syncWorker.php) — Async CLI process spawned by webhooks viaexec()or by the safety cron. Claims and processes queued jobs with a configurable timeout (default 240s). - Safety Net (
crontasks/syncSafety.php) — Hourly cron that resets stuck jobs (>10min), spawns workers for pending jobs, runs a 24-hour health check (auto-enqueues full sync if no webhooks received), and purges old data.
Admin UI
- Queue Status Dashboard — New card on Sync Status page showing pending/processing/completed/failed/skipped counts, recent jobs table with real-time refresh, worker status badge, and action buttons:
- Full Sync — Enqueues catalog sync for all active auctions
- Sync Selected — Enqueue a single auction from dropdown
- Spawn Worker — Manually trigger a background worker process
- Live Console — Dark-themed terminal console on the Sync Status page. Polls
af_sync_logevery 1.5s showing timestamped, color-coded log entries from webhooks, workers, queue operations, and the safety cron. Supports pause, clear, and auto-scroll.
Cron Changes
- Removed
importData(ran every minute — ~1,440 PHP executions/day) - Removed
importBidSpirit(ran hourly — ~24 PHP executions/day) - Added
syncSafety(runs hourly at :10 — 24 PHP executions/day) - Net effect: ~62 PHP executions/hour → 1 PHP execution/hour
- WP-Cron safety hook (
auctionforge_sync_safety) — Always-active hourly event, independent of external cron - setup.sh v3 — Updated task definitions, new
migratecommand for interactive v2→v3 transition
Database
- New table:
af_sync_queue— Job queue with status, priority, source, attempts, worker PID, timing columns - New table:
af_sync_log— Real-time log entries with context, level, auction_id, job_id - DB version: 20 → 22
Constants Added
| Constant | Default | Description |
|---|---|---|
|
AUCTIONFORGE_SYNC_WORKER_TIMEOUT| 240 | Worker process timeout in seconds ||
AUCTIONFORGE_SYNC_STALE_JOB| 600 | Seconds before a processing job is considered stuck ||
AUCTIONFORGE_SYNC_HEALTH_CHECK| 86400 | Seconds without webhook before triggering full sync ||
AUCTIONFORGE_SYNC_LOG_RETENTION| 7 | Days to keep log entries ||
AUCTIONFORGE_SYNC_QUEUE_RETENTION| 30 | Days to keep completed queue jobs ||
AUCTIONFORGE_CURL_TIMEOUT| 30 | BidSpirit API cURL timeout in seconds ||
AUCTIONFORGE_PHP_BINARY| /www/server/php/83/bin/php | PHP CLI binary path for spawning workers |AJAX Handlers Added
auctionforge_sync_log_poll— Incremental log polling for live consoleauctionforge_sync_queue_status— Queue counts + recent jobs for dashboardauctionforge_sync_enqueue— Admin-triggered sync actions (full_sync, sync_auction, spawn_worker)
Fixes
- cURL timeout — BidSpiritRequest now enforces a 30-second timeout (was unlimited/0), preventing hung connections from blocking the sync pipeline.
Files Changed
- Modified:
auctionforge.php,inc/coreIncludes.php,inc/controllers/AuctionsAPI.php,inc/BidSpiritRequest.php,admin/view/sync-status.php,crontasks/setup.sh - Created:
inc/sync/SyncQueue.php,inc/sync/SyncLogger.php,inc/sync/CatalogSyncWorker.php,inc/sync/ItemUpdateWorker.php,crontasks/syncWorker.php,crontasks/syncSafety.php
---
[2.7.3.0]
Fixes
- Various stability improvements and bug fixes.
[2.7.1.2]
Fixes
- Added missing
vatAndCommission()function inloadBid()— the sales tax display on single lot pages was never being rendered because the code to callloadTemplateforvat-and-commission-templatewas missing fromapp.js.
[2.7.1.1]
Fixes
- 2 decimal places now only appear in the bid modal (Your max bid, Total Price) via
showDecimalsflag. 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.
[2.7.0.9]
Fixes
- Fixed fatal error during plugin install/upgrade:
class-stats-database.phprequire failure.
[2.7.0.0]
New Features: Advanced Lot Analytics
- Conversion Tracking, Peak Viewing Times, Pre-Sale vs Live Comparison, Category Performance, Share Analytics, Search → View Funnel, Click-Through Tracking, CSV Export, Hot Lot Badge.
- New DB table:
af_lot_shares. New columns onaf_lot_analytics. DB version bumped to 20.
[2.6.0.0]
New Feature: Lot Analytics
- Comprehensive lot view and favorite tracking system with admin dashboard.
[2.5.0.0]
New Features
- Site Statistics System — Full website analytics built into the plugin admin.
- Recently Viewed Items — Profile page tab showing last 20 viewed lots per user.
- Namespace resolution — Fixed fatal error in
-
v3.6.0.15 Stable Apr 20, 2026Download v3.6.0.15📦 8.94 MB⚙️ WP 5.2+🔧 PHP 7.2+✓ Tested 6.4
AuctionForge Changelog
All notable changes to the AuctionForge plugin are documented in this file.
---
[3.6.0.7] — 2026-04-14
Hotfix
Fixes
- Namespace resolution — Fixed fatal error in
wp_footercommission label hook caused by unqualifiedSettingsHelperandSettingsclass references. Now uses fully qualified namespaces.
Files Changed
- Modified:
auctionforge.php
---
[3.6.0.6] — 2026-04-14
Commission Label Override Fix
Fixes
- Theme template override compatibility — Moved the commission label JS override from the
single-lot.phptemplate intoauctionforge.phpviawp_footerhook (priority 99). Sites with theme-level template overrides (e.g.themes/*/auctionforge/single-lot.php) were not picking up the inline script. Thewp_footerapproach works universally on all single lot pages.
Files Changed
- Modified:
auctionforge.php,templates/single-lot.php
---
[3.6.0.5] — 2026-04-14
Commission Label Override
Features
- Commission Label Setting — New dropdown in Settings → Appearance allowing admins to choose between "Buyer's Premium" (default) and "Auction House Commission" as the label displayed on lot pages. This overrides the Bidspirit JS client's default label using a MutationObserver that catches asynchronously injected text.
Files Changed
- Modified:
inc/controllers/Settings.php,templates/single-lot.php
---
[3.6.0.4] — 2026-04-12
Auction Approval Modal Redesign
Changes
- Removed BidSpirit Terms of Use — The generic BidSpirit "Terms of Use" section that appeared at the top of the non-credit-card approval modal has been removed. The modal now shows only the auction house's own legal agreements managed within the plugin.
- Renamed Modal Title — Changed "Terms of conditions" to "Terms & Conditions".
- Larger Scroll Area — The Terms & Conditions scroll box is now 350px tall (up from 200px) for easier reading.
- Proportional Section Heights — Refund & Return Policy and Chargeback Waiver sections use a shorter 260px scroll box to visually distinguish them from the primary Terms & Conditions.
Files Changed
- Modified:
templates/js-chunks/approval-info.php,assets/js/app.js
---
[3.6.0.2] — 2026-04-10
Webhook Token Generator
Features
- Token Generator Widget — Added a 16-character random token generator directly below the "Webhook auth token" field on the Settings page. Includes a "Generate Token" button and a clipboard copy icon with visual feedback.
Files Changed
- Modified:
inc/controllers/Settings.php
---
[3.6.0.1] — 2026-04-10
Patch
Changes
- Version bump.
---
[3.6.0.0] — 2026-04-10
Legal Agreements for Auction Approval
Features
- Terms & Conditions — A mandatory, scrollable Terms & Conditions document is now displayed during the auction approval process. Bidders must scroll to the bottom and check an agreement box before their approval request is submitted. Always enabled.
- Refund & Return Policy — An optional, scrollable Refund & Return Policy can be enabled in Settings. When enabled, bidders must read and accept it during auction approval.
- Chargeback Waiver — An optional, scrollable Chargeback Waiver can be enabled in Settings. When enabled, bidders must read and accept it during auction approval.
- Admin Management — New "Legal Agreements" page under the Bidspirit admin menu with tabbed TinyMCE editors for each agreement type. Includes automatic version numbering (incremented on content change) and full version history.
- Consent Logging — Every agreement acceptance is logged to a dedicated database table (
af_user_agreement_log) with the agreement type, version, user email, IP address, user agent, auction ID, and timestamp. - User Tracking Integration — Agreement events (
terms_agreement,refund_agreement,chargeback_waiver) are also recorded in the existing IP tracking system alongside registration, login, and bid events. - Placeholder Content — Default sample content is seeded on plugin activation for all three agreement types.
Settings Added
- Enable Refund & Return Policy — Toggle to require bidders to accept the refund policy during auction approval.
- Enable Chargeback Waiver — Toggle to require bidders to accept the chargeback waiver during auction approval.
Database
- New table:
af_legal_agreements— Current active agreement content per type - New table:
af_legal_agreement_versions— Version history archive - New table:
af_user_agreement_log— User consent records
Files Changed
- Modified:
auctionforge.php,inc/controllers/Settings.php,inc/controllers/BidspiritViews.php,inc/ip-logger.php,templates/js-chunks/approval-info.php,assets/js/app.js - Created:
inc/legal/class-legal-agreements.php,admin/view/legal-agreements.php
---
[3.5.0.6] — 2026-04-08
Bid Event Tracking
Features
- Bid Tracking — All successful bids (regular, catalog, pre-sale buyout, post-sale purchase) now fire
afLogIP("bid", bidspiritUser)to capture the bidder's full identity in the user tracking table. - Whitelist Update — Added
bidto the allowedevent_typevalues in both the local plugin and the central WPDeploy API.
---
[3.5.0.5] — 2026-04-08
Self-Healing Database Schema
Features
- Auto-Migration — The plugin now auto-detects and adds any missing tracking table columns on version upgrade, ensuring sites with older schemas seamlessly migrate without manual SQL.
---
[3.5.0.4] — 2026-04-08
API Key Auto-Healing
Features
- Seamless Self-Registration — The WordPress plugin now autonomously regenerates and saves a fresh API Key whenever WPDeploy rejects a payload with an
api_key_collisionerror. This guarantees zero-downtime security handovers when developers clone instances to proxy/staging servers.
---
[3.5.0.3] — 2026-04-08
API Key Collision Defense
Features
- 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_collisionerrors, directly instructing developers to update cloned keys.
---
[3.5.0.2] — 2026-04-08
Modal Trigger Hotfix
Fixes
- Restructured internal UI rendering priority to gracefully deploy the inline Modal triggers inside custom IP log view without colliding with cached
z-indexstacks.
---
[3.5.0.1] — 2026-04-08
Hotfix
Fixes
- Timed Auction Badge Visibility — Fixed a strict type-matching bug in the main
auction_list.phpcore file that incorrectly hid the "Timed Auction" badge overlay from valid timed/online auctions on the main upcoming/archive views. The badge now displays properly across all manual and Bidspirit-synced objects when toggled on.
Files Changed
- Modified:
templates/main/auction_list.php
---
[3.2.9.1] — 2026-03-30
Timed Auction Display Enhancements
Features
- Timed Auction Countdown Text Toggle — Added a WP-Admin setting "Change text to 'Auction will close in'" that conditionally changes the countdown label for timed/online auctions on single lot pages.
- Shortcode Text Toggle Support — Extended the new countdown text logic to the
bp_upcoming_wideshortcodes so "Live bidding starts in:" successfully transitions to "Auction will close in:" for timed auctions.
Files Changed
- Modified:
inc/controllers/Settings.php,templates/single-lot.php,templates/shortcodes/upcoming-auction-wide.php,templates/shortcodes/upcoming-auction-wide-manual.php
---
[3.2.9.0] — 2026-03-29
Billing & Invoices Polish
Fixes
- Profile Invoice ID Tracking — Prevented internal auction codes (e.g.
002orai4) from breaking into the clean hyphenated titles inside theprofile-templates.phpview. - Dynamic Payment Statuses — Replaced Bidspirit's default/cached
NOT PAIDHTML payloads by wiring thedompdfgenerator to directly respect the current$b.statusstring from the API (resolving instances where a paid invoice still printed "NOT PAID" atop the document). - Payment Instructions Conditional — Automatically hide the "Payment Instructions" block from the PDF footer when an invoice is fully paid.
- Improved Nomenclature — Changed "Invoice No:" to "Bidder No:" on document output to prevent confusion with static invoice ledger IDs.
---
[3.2.6.0] — 2026-03-28
Multi-Day Auction Lot Filtering Fix
Fixes
- Day 2+ showing lots from Day 1 in multi-day auctions — The
itemIndexcolumn inbp_meta_dataisvarchar(55), but the day-range filter inBidspiritQuery::bp_query_where()was comparing it as a string. With string comparison, lot numbers like'11','101'–'145'incorrectly fell between'1001'and'1450', causing Day 1 lots to leak into Day 2 results. Fixed by usingCAST(bpMeta.itemIndex AS UNSIGNED)for numeric comparison andintval()on the PHP-side boundary values. Letter lots (e.g.14A,1025A) are handled correctly —CASTstrips the suffix, keeping them grouped with their base lot number.
Files Changed
- Modified:
inc/controllers/BidspiritQuery.php
---
[3.2.5.9] — 2026-03-27
Catalog Page Fix
Fixes
- Duplicate preview hours on catalog pages — The
displayHoursfield was rendered twice: once via thebp_after_description_auctionhook inBidspiritViews.phpand once inline in the auction template. Removed the hook-based rendering to eliminate the duplication.
Files Changed
- Modified:
inc/controllers/BidspiritViews.php,templates/main/auction.php
---
[3.2.5] — 2026-03-19
Sync Reliability & Stuck Lot Prevention
Fixes
- CATALOG_PUBLISHED webhook now triggers catalog sync — Previously only sent push notifications without syncing lots. When the earlier AUCTION_CATALOG_UPDATED fired before the catalog was ready on BidSpirit, lots were never imported. CATALOG_PUBLISHED now calls
auctionCatalogUpdated()to trigger a full catalog sync when the catalog is actually available. - 0-lot API results now fail instead of silently succeeding — When BidSpirit API returns 0 lots (catalog not yet ready), the sync job now fails with an explicit error message, allowing the next webhook to create a fresh retry job.
- Expanded CDN allowlist in pre_http_request filter — The HTTP filter during bulk post insertion now allows all
*.bidspirit.comsubdomains and BidSpirit image CDNs (fastly.net,cloudfront.net). Previously onlybidspirit.comandwww.bidspirit.comwere allowed, blocking image downloads during sync and causing worker hangs. - InsertLotsBS timeout guard — Stage 5 (InsertLotsBS processing loop) now has a 180-second timeout and logs progress every 2 batches. Prevents indefinite hangs that previously required manual force-kill.
- fixResult() no longer marks lots as done when postId=0 — When
lotProcessing()fails to create a WP post, the staging row now keepssyncFinished=0so the lot is retried on the next sync pass, instead of being permanently marked as complete with no actual post. - lotProcessing() logs error on missing auction term — Previously returned 0 silently when
Auction::findAuctionById()failed. Now logs an explicit error that feeds intofixResult()to keep the lot retryable. - Hourly orphan detection in safety cron — New step in
syncSafety.phpdetects lot posts that exist inbp_meta_databut are missing their auction taxonomy assignment (caused by workers killed mid-batch) and auto-repairs them withwp_set_object_terms().
Files Changed
- Modified:
inc/controllers/AuctionsAPI.php,inc/sync/CatalogSyncWorker.php,inc/abs/InsertLotsAbstract.php,inc/import/InsertLotsBS.php,crontasks/syncSafety.php
---
[3.2.4] — 2026-03-18
Sync Worker Hang Fix
Fixes
- Sync workers hanging at InsertLotsBS stage — Third-party plugins (Smush Pro, SmartCrawl SEO, WPMU DEV Updates) hook into
wp_insert_post()and make blocking outbound HTTPS calls for every lot processed. With 489+ lots per auction, this caused workers to hang indefinitely on socket reads to WPMU DEV servers (32.193.94.25,32.193.93.106). AddedWP_IMPORTINGconstant at the REST worker entry point and apre_http_requestfilter inCatalogSyncWorkerthat blocks all non-essential external HTTP during the batch post-insertion phase. Loopback (127.0.0.1,localhost) and BidSpirit API calls remain allowed. - Stuck staging rows after force-kill — When workers were force-killed mid-sync, staging rows in
import_historywere left withsyncstart=1and never unblocked. Subsequent sync runs could not see these rows (filtered out byLot::getRawLots()), causing the InsertLotsBS loop to exit immediately with 0 posts processed. Combined with job deduplication (SyncQueue::enqueue()skips if aprocessingjob exists), this created a deadlock where no new sync could proceed.
Files Changed
- Modified:
auctionforge.php,inc/sync/CatalogSyncWorker.php
---
[3.2.2] — 2026-03-17
Full Sync Auction Discovery Fix
Fixes
- Full Sync finds no auctions on fresh sites — The v3
full_syncaction only queried the WordPress database for existing auction terms, but on a freshly deployed site the database has zero auctions. AddedAuctionList::init()discovery step before querying the DB, so Full Sync now fetches all auctions from the BidSpirit API and creates taxonomy terms first, then enqueues catalog sync jobs for each.
Files Changed
- Modified:
auctionforge.php
---
[3.2.0] — 2026-03-14
Webhook Pipeline Fixes, Archive Sync & Admin UI Overhaul
New Features
- Archive Sync — New "Archive Sync" button on Sync Status admin page. Enqueues catalog sync jobs for all ARCHIVED/ENDED auctions. Past auctions now appear in the auction dropdown with an optgroup separator and state label.
- Sync Tasks v3 — Replaced old v2 task cards (importData, importBidSpirit, lotBidSpiritOld) with v3 queue-based tasks. "Sync Active Auctions" and "Sync Archived Auctions" now enqueue jobs via the queue system. Maintenance tasks (Clean Draft/Trash Lots, Clean Orphaned Meta) remain as direct-execution tasks.
- How It Works guide rewritten — Complete rewrite of the admin guide for v3 architecture. Documents webhook-first flow, all 5 job types, queue system mechanics, cron setup (external + WP-Cron), configuration constants, and troubleshooting.
Fixes
- Dual-write removed — Removed legacy handlers from
auctionCatalogUpdated(),auctionDayEnded(), anditemsUpdated()webhook methods. The old handlers were racing with the v3 worker, creating orphaned staging rows inimport_historythat were never processed. All three methods now exclusively use the v3 enqueue → spawn path. - ITEMS_UPDATED webhook — Fixed
itemsUpdated()failing to enqueue jobs. TheITEMS_UPDATEDpayload hasauctionIdnested initemsByLanguage.{lang}[0].item.auctionId, not at the top level. Added extraction logic to resolve it. - ItemUpdateWorker incomplete —
ItemUpdateWorker::process()was only callingLot::bulkSave()(staging table) without runningInsertLotsBSto process staged data into WP posts andbp_meta_data. Added the InsertLotsBS processing step with autocommit restore. Item updates now flow: stage → InsertLotsBS → WP post + meta → cache clear. - Worker spawn reliability — Changed
SyncQueue::spawnWorker()from non-blocking HTTPS to blocking HTTP loopback (http://127.0.0.1with explicitHostheader, 2s timeout). Fixes nginx 403/404 errors when HTTPS loopback hits the default vhost instead of the site's vhost. - API token constant — Plugin expects
AUCTIONFORGE_API_TOKENinwp-config.php(renamed fromUCO_API_TOKENduring the plugin rename). Documented in readme.
Database
- DB version: 22 → 23
Files Changed
- Modified:
inc/controllers/AuctionsAPI.php,inc/sync/ItemUpdateWorker.php,inc/sync/SyncQueue.php,auctionforge.php,admin/view/sync-status.php,readme.txt
---
[3.0.0] — 2025-03-14
New Feature: Webhook-First Sync Architecture (Sync v3)
Overview: Complete redesign of the BidSpirit data synchronisation pipeline. Replaces the old two-phase polling system (importBidSpirit every hour + importData every minute) with a webhook-driven job queue that processes data in near real-time.
Architecture
- 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: webhook → queue → background worker → WordPress posts. - Dual-write mode — During transition, webhooks enqueue jobs AND still run the legacy handlers. Once verified, legacy handlers can be removed cleanly.
- Job deduplication — Prevents duplicate work by checking for existing pending/processing jobs with the same auction_id + job_type.
New Components
- Job Queue System (
inc/sync/SyncQueue.php) — Priority-based FIFO queue with atomic job claiming, status tracking (pending/processing/completed/failed/skipped), worker PID tracking, and automatic stuck job recovery. - Sync Logger (
inc/sync/SyncLogger.php) — Real-time log table for admin console polling with level filtering (info/success/warning/error) and incremental cursor-based retrieval. - Catalog Sync Worker (
inc/sync/CatalogSyncWorker.php) — Processes catalog_sync, full_sync, and day_ended jobs by reusing existingLotList::singleRun()logic. - Item Update Worker (
inc/sync/ItemUpdateWorker.php) — Processes individual item_update jobs with the same logic as the webhookitemsUpdatedhandler. - Background Worker (
crontasks/syncWorker.php) — Async CLI process spawned by webhooks viaexec()or by the safety cron. Claims and processes queued jobs with a configurable timeout (default 240s). - Safety Net (
crontasks/syncSafety.php) — Hourly cron that resets stuck jobs (>10min), spawns workers for pending jobs, runs a 24-hour health check (auto-enqueues full sync if no webhooks received), and purges old data.
Admin UI
- Queue Status Dashboard — New card on Sync Status page showing pending/processing/completed/failed/skipped counts, recent jobs table with real-time refresh, worker status badge, and action buttons:
- Full Sync — Enqueues catalog sync for all active auctions
- Sync Selected — Enqueue a single auction from dropdown
- Spawn Worker — Manually trigger a background worker process
- Live Console — Dark-themed terminal console on the Sync Status page. Polls
af_sync_logevery 1.5s showing timestamped, color-coded log entries from webhooks, workers, queue operations, and the safety cron. Supports pause, clear, and auto-scroll.
Cron Changes
- Removed
importData(ran every minute — ~1,440 PHP executions/day) - Removed
importBidSpirit(ran hourly — ~24 PHP executions/day) - Added
syncSafety(runs hourly at :10 — 24 PHP executions/day) - Net effect: ~62 PHP executions/hour → 1 PHP execution/hour
- WP-Cron safety hook (
auctionforge_sync_safety) — Always-active hourly event, independent of external cron - setup.sh v3 — Updated task definitions, new
migratecommand for interactive v2→v3 transition
Database
- New table:
af_sync_queue— Job queue with status, priority, source, attempts, worker PID, timing columns - New table:
af_sync_log— Real-time log entries with context, level, auction_id, job_id - DB version: 20 → 22
Constants Added
| Constant | Default | Description |
|---|---|---|
|
AUCTIONFORGE_SYNC_WORKER_TIMEOUT| 240 | Worker process timeout in seconds ||
AUCTIONFORGE_SYNC_STALE_JOB| 600 | Seconds before a processing job is considered stuck ||
AUCTIONFORGE_SYNC_HEALTH_CHECK| 86400 | Seconds without webhook before triggering full sync ||
AUCTIONFORGE_SYNC_LOG_RETENTION| 7 | Days to keep log entries ||
AUCTIONFORGE_SYNC_QUEUE_RETENTION| 30 | Days to keep completed queue jobs ||
AUCTIONFORGE_CURL_TIMEOUT| 30 | BidSpirit API cURL timeout in seconds ||
AUCTIONFORGE_PHP_BINARY| /www/server/php/83/bin/php | PHP CLI binary path for spawning workers |AJAX Handlers Added
auctionforge_sync_log_poll— Incremental log polling for live consoleauctionforge_sync_queue_status— Queue counts + recent jobs for dashboardauctionforge_sync_enqueue— Admin-triggered sync actions (full_sync, sync_auction, spawn_worker)
Fixes
- cURL timeout — BidSpiritRequest now enforces a 30-second timeout (was unlimited/0), preventing hung connections from blocking the sync pipeline.
Files Changed
- Modified:
auctionforge.php,inc/coreIncludes.php,inc/controllers/AuctionsAPI.php,inc/BidSpiritRequest.php,admin/view/sync-status.php,crontasks/setup.sh - Created:
inc/sync/SyncQueue.php,inc/sync/SyncLogger.php,inc/sync/CatalogSyncWorker.php,inc/sync/ItemUpdateWorker.php,crontasks/syncWorker.php,crontasks/syncSafety.php
---
[2.7.3.0]
Fixes
- Various stability improvements and bug fixes.
[2.7.1.2]
Fixes
- Added missing
vatAndCommission()function inloadBid()— the sales tax display on single lot pages was never being rendered because the code to callloadTemplateforvat-and-commission-templatewas missing fromapp.js.
[2.7.1.1]
Fixes
- 2 decimal places now only appear in the bid modal (Your max bid, Total Price) via
showDecimalsflag. 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.
[2.7.0.9]
Fixes
- Fixed fatal error during plugin install/upgrade:
class-stats-database.phprequire failure.
[2.7.0.0]
New Features: Advanced Lot Analytics
- Conversion Tracking, Peak Viewing Times, Pre-Sale vs Live Comparison, Category Performance, Share Analytics, Search → View Funnel, Click-Through Tracking, CSV Export, Hot Lot Badge.
- New DB table:
af_lot_shares. New columns onaf_lot_analytics. DB version bumped to 20.
[2.6.0.0]
New Feature: Lot Analytics
- Comprehensive lot view and favorite tracking system with admin dashboard.
[2.5.0.0]
New Features
- Site Statistics System — Full website analytics built into the plugin admin.
- Recently Viewed Items — Profile page tab showing last 20 viewed lots per user.
- Namespace resolution — Fixed fatal error in
-
v3.6.0.13 Stable Apr 20, 2026Download v3.6.0.13📦 8.94 MB⚙️ WP 5.2+🔧 PHP 7.2+✓ Tested 6.4
AuctionForge Changelog
All notable changes to the AuctionForge plugin are documented in this file.
---
[3.6.0.7] — 2026-04-14
Hotfix
Fixes
- Namespace resolution — Fixed fatal error in
wp_footercommission label hook caused by unqualifiedSettingsHelperandSettingsclass references. Now uses fully qualified namespaces.
Files Changed
- Modified:
auctionforge.php
---
[3.6.0.6] — 2026-04-14
Commission Label Override Fix
Fixes
- Theme template override compatibility — Moved the commission label JS override from the
single-lot.phptemplate intoauctionforge.phpviawp_footerhook (priority 99). Sites with theme-level template overrides (e.g.themes/*/auctionforge/single-lot.php) were not picking up the inline script. Thewp_footerapproach works universally on all single lot pages.
Files Changed
- Modified:
auctionforge.php,templates/single-lot.php
---
[3.6.0.5] — 2026-04-14
Commission Label Override
Features
- Commission Label Setting — New dropdown in Settings → Appearance allowing admins to choose between "Buyer's Premium" (default) and "Auction House Commission" as the label displayed on lot pages. This overrides the Bidspirit JS client's default label using a MutationObserver that catches asynchronously injected text.
Files Changed
- Modified:
inc/controllers/Settings.php,templates/single-lot.php
---
[3.6.0.4] — 2026-04-12
Auction Approval Modal Redesign
Changes
- Removed BidSpirit Terms of Use — The generic BidSpirit "Terms of Use" section that appeared at the top of the non-credit-card approval modal has been removed. The modal now shows only the auction house's own legal agreements managed within the plugin.
- Renamed Modal Title — Changed "Terms of conditions" to "Terms & Conditions".
- Larger Scroll Area — The Terms & Conditions scroll box is now 350px tall (up from 200px) for easier reading.
- Proportional Section Heights — Refund & Return Policy and Chargeback Waiver sections use a shorter 260px scroll box to visually distinguish them from the primary Terms & Conditions.
Files Changed
- Modified:
templates/js-chunks/approval-info.php,assets/js/app.js
---
[3.6.0.2] — 2026-04-10
Webhook Token Generator
Features
- Token Generator Widget — Added a 16-character random token generator directly below the "Webhook auth token" field on the Settings page. Includes a "Generate Token" button and a clipboard copy icon with visual feedback.
Files Changed
- Modified:
inc/controllers/Settings.php
---
[3.6.0.1] — 2026-04-10
Patch
Changes
- Version bump.
---
[3.6.0.0] — 2026-04-10
Legal Agreements for Auction Approval
Features
- Terms & Conditions — A mandatory, scrollable Terms & Conditions document is now displayed during the auction approval process. Bidders must scroll to the bottom and check an agreement box before their approval request is submitted. Always enabled.
- Refund & Return Policy — An optional, scrollable Refund & Return Policy can be enabled in Settings. When enabled, bidders must read and accept it during auction approval.
- Chargeback Waiver — An optional, scrollable Chargeback Waiver can be enabled in Settings. When enabled, bidders must read and accept it during auction approval.
- Admin Management — New "Legal Agreements" page under the Bidspirit admin menu with tabbed TinyMCE editors for each agreement type. Includes automatic version numbering (incremented on content change) and full version history.
- Consent Logging — Every agreement acceptance is logged to a dedicated database table (
af_user_agreement_log) with the agreement type, version, user email, IP address, user agent, auction ID, and timestamp. - User Tracking Integration — Agreement events (
terms_agreement,refund_agreement,chargeback_waiver) are also recorded in the existing IP tracking system alongside registration, login, and bid events. - Placeholder Content — Default sample content is seeded on plugin activation for all three agreement types.
Settings Added
- Enable Refund & Return Policy — Toggle to require bidders to accept the refund policy during auction approval.
- Enable Chargeback Waiver — Toggle to require bidders to accept the chargeback waiver during auction approval.
Database
- New table:
af_legal_agreements— Current active agreement content per type - New table:
af_legal_agreement_versions— Version history archive - New table:
af_user_agreement_log— User consent records
Files Changed
- Modified:
auctionforge.php,inc/controllers/Settings.php,inc/controllers/BidspiritViews.php,inc/ip-logger.php,templates/js-chunks/approval-info.php,assets/js/app.js - Created:
inc/legal/class-legal-agreements.php,admin/view/legal-agreements.php
---
[3.5.0.6] — 2026-04-08
Bid Event Tracking
Features
- Bid Tracking — All successful bids (regular, catalog, pre-sale buyout, post-sale purchase) now fire
afLogIP("bid", bidspiritUser)to capture the bidder's full identity in the user tracking table. - Whitelist Update — Added
bidto the allowedevent_typevalues in both the local plugin and the central WPDeploy API.
---
[3.5.0.5] — 2026-04-08
Self-Healing Database Schema
Features
- Auto-Migration — The plugin now auto-detects and adds any missing tracking table columns on version upgrade, ensuring sites with older schemas seamlessly migrate without manual SQL.
---
[3.5.0.4] — 2026-04-08
API Key Auto-Healing
Features
- Seamless Self-Registration — The WordPress plugin now autonomously regenerates and saves a fresh API Key whenever WPDeploy rejects a payload with an
api_key_collisionerror. This guarantees zero-downtime security handovers when developers clone instances to proxy/staging servers.
---
[3.5.0.3] — 2026-04-08
API Key Collision Defense
Features
- 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_collisionerrors, directly instructing developers to update cloned keys.
---
[3.5.0.2] — 2026-04-08
Modal Trigger Hotfix
Fixes
- Restructured internal UI rendering priority to gracefully deploy the inline Modal triggers inside custom IP log view without colliding with cached
z-indexstacks.
---
[3.5.0.1] — 2026-04-08
Hotfix
Fixes
- Timed Auction Badge Visibility — Fixed a strict type-matching bug in the main
auction_list.phpcore file that incorrectly hid the "Timed Auction" badge overlay from valid timed/online auctions on the main upcoming/archive views. The badge now displays properly across all manual and Bidspirit-synced objects when toggled on.
Files Changed
- Modified:
templates/main/auction_list.php
---
[3.2.9.1] — 2026-03-30
Timed Auction Display Enhancements
Features
- Timed Auction Countdown Text Toggle — Added a WP-Admin setting "Change text to 'Auction will close in'" that conditionally changes the countdown label for timed/online auctions on single lot pages.
- Shortcode Text Toggle Support — Extended the new countdown text logic to the
bp_upcoming_wideshortcodes so "Live bidding starts in:" successfully transitions to "Auction will close in:" for timed auctions.
Files Changed
- Modified:
inc/controllers/Settings.php,templates/single-lot.php,templates/shortcodes/upcoming-auction-wide.php,templates/shortcodes/upcoming-auction-wide-manual.php
---
[3.2.9.0] — 2026-03-29
Billing & Invoices Polish
Fixes
- Profile Invoice ID Tracking — Prevented internal auction codes (e.g.
002orai4) from breaking into the clean hyphenated titles inside theprofile-templates.phpview. - Dynamic Payment Statuses — Replaced Bidspirit's default/cached
NOT PAIDHTML payloads by wiring thedompdfgenerator to directly respect the current$b.statusstring from the API (resolving instances where a paid invoice still printed "NOT PAID" atop the document). - Payment Instructions Conditional — Automatically hide the "Payment Instructions" block from the PDF footer when an invoice is fully paid.
- Improved Nomenclature — Changed "Invoice No:" to "Bidder No:" on document output to prevent confusion with static invoice ledger IDs.
---
[3.2.6.0] — 2026-03-28
Multi-Day Auction Lot Filtering Fix
Fixes
- Day 2+ showing lots from Day 1 in multi-day auctions — The
itemIndexcolumn inbp_meta_dataisvarchar(55), but the day-range filter inBidspiritQuery::bp_query_where()was comparing it as a string. With string comparison, lot numbers like'11','101'–'145'incorrectly fell between'1001'and'1450', causing Day 1 lots to leak into Day 2 results. Fixed by usingCAST(bpMeta.itemIndex AS UNSIGNED)for numeric comparison andintval()on the PHP-side boundary values. Letter lots (e.g.14A,1025A) are handled correctly —CASTstrips the suffix, keeping them grouped with their base lot number.
Files Changed
- Modified:
inc/controllers/BidspiritQuery.php
---
[3.2.5.9] — 2026-03-27
Catalog Page Fix
Fixes
- Duplicate preview hours on catalog pages — The
displayHoursfield was rendered twice: once via thebp_after_description_auctionhook inBidspiritViews.phpand once inline in the auction template. Removed the hook-based rendering to eliminate the duplication.
Files Changed
- Modified:
inc/controllers/BidspiritViews.php,templates/main/auction.php
---
[3.2.5] — 2026-03-19
Sync Reliability & Stuck Lot Prevention
Fixes
- CATALOG_PUBLISHED webhook now triggers catalog sync — Previously only sent push notifications without syncing lots. When the earlier AUCTION_CATALOG_UPDATED fired before the catalog was ready on BidSpirit, lots were never imported. CATALOG_PUBLISHED now calls
auctionCatalogUpdated()to trigger a full catalog sync when the catalog is actually available. - 0-lot API results now fail instead of silently succeeding — When BidSpirit API returns 0 lots (catalog not yet ready), the sync job now fails with an explicit error message, allowing the next webhook to create a fresh retry job.
- Expanded CDN allowlist in pre_http_request filter — The HTTP filter during bulk post insertion now allows all
*.bidspirit.comsubdomains and BidSpirit image CDNs (fastly.net,cloudfront.net). Previously onlybidspirit.comandwww.bidspirit.comwere allowed, blocking image downloads during sync and causing worker hangs. - InsertLotsBS timeout guard — Stage 5 (InsertLotsBS processing loop) now has a 180-second timeout and logs progress every 2 batches. Prevents indefinite hangs that previously required manual force-kill.
- fixResult() no longer marks lots as done when postId=0 — When
lotProcessing()fails to create a WP post, the staging row now keepssyncFinished=0so the lot is retried on the next sync pass, instead of being permanently marked as complete with no actual post. - lotProcessing() logs error on missing auction term — Previously returned 0 silently when
Auction::findAuctionById()failed. Now logs an explicit error that feeds intofixResult()to keep the lot retryable. - Hourly orphan detection in safety cron — New step in
syncSafety.phpdetects lot posts that exist inbp_meta_databut are missing their auction taxonomy assignment (caused by workers killed mid-batch) and auto-repairs them withwp_set_object_terms().
Files Changed
- Modified:
inc/controllers/AuctionsAPI.php,inc/sync/CatalogSyncWorker.php,inc/abs/InsertLotsAbstract.php,inc/import/InsertLotsBS.php,crontasks/syncSafety.php
---
[3.2.4] — 2026-03-18
Sync Worker Hang Fix
Fixes
- Sync workers hanging at InsertLotsBS stage — Third-party plugins (Smush Pro, SmartCrawl SEO, WPMU DEV Updates) hook into
wp_insert_post()and make blocking outbound HTTPS calls for every lot processed. With 489+ lots per auction, this caused workers to hang indefinitely on socket reads to WPMU DEV servers (32.193.94.25,32.193.93.106). AddedWP_IMPORTINGconstant at the REST worker entry point and apre_http_requestfilter inCatalogSyncWorkerthat blocks all non-essential external HTTP during the batch post-insertion phase. Loopback (127.0.0.1,localhost) and BidSpirit API calls remain allowed. - Stuck staging rows after force-kill — When workers were force-killed mid-sync, staging rows in
import_historywere left withsyncstart=1and never unblocked. Subsequent sync runs could not see these rows (filtered out byLot::getRawLots()), causing the InsertLotsBS loop to exit immediately with 0 posts processed. Combined with job deduplication (SyncQueue::enqueue()skips if aprocessingjob exists), this created a deadlock where no new sync could proceed.
Files Changed
- Modified:
auctionforge.php,inc/sync/CatalogSyncWorker.php
---
[3.2.2] — 2026-03-17
Full Sync Auction Discovery Fix
Fixes
- Full Sync finds no auctions on fresh sites — The v3
full_syncaction only queried the WordPress database for existing auction terms, but on a freshly deployed site the database has zero auctions. AddedAuctionList::init()discovery step before querying the DB, so Full Sync now fetches all auctions from the BidSpirit API and creates taxonomy terms first, then enqueues catalog sync jobs for each.
Files Changed
- Modified:
auctionforge.php
---
[3.2.0] — 2026-03-14
Webhook Pipeline Fixes, Archive Sync & Admin UI Overhaul
New Features
- Archive Sync — New "Archive Sync" button on Sync Status admin page. Enqueues catalog sync jobs for all ARCHIVED/ENDED auctions. Past auctions now appear in the auction dropdown with an optgroup separator and state label.
- Sync Tasks v3 — Replaced old v2 task cards (importData, importBidSpirit, lotBidSpiritOld) with v3 queue-based tasks. "Sync Active Auctions" and "Sync Archived Auctions" now enqueue jobs via the queue system. Maintenance tasks (Clean Draft/Trash Lots, Clean Orphaned Meta) remain as direct-execution tasks.
- How It Works guide rewritten — Complete rewrite of the admin guide for v3 architecture. Documents webhook-first flow, all 5 job types, queue system mechanics, cron setup (external + WP-Cron), configuration constants, and troubleshooting.
Fixes
- Dual-write removed — Removed legacy handlers from
auctionCatalogUpdated(),auctionDayEnded(), anditemsUpdated()webhook methods. The old handlers were racing with the v3 worker, creating orphaned staging rows inimport_historythat were never processed. All three methods now exclusively use the v3 enqueue → spawn path. - ITEMS_UPDATED webhook — Fixed
itemsUpdated()failing to enqueue jobs. TheITEMS_UPDATEDpayload hasauctionIdnested initemsByLanguage.{lang}[0].item.auctionId, not at the top level. Added extraction logic to resolve it. - ItemUpdateWorker incomplete —
ItemUpdateWorker::process()was only callingLot::bulkSave()(staging table) without runningInsertLotsBSto process staged data into WP posts andbp_meta_data. Added the InsertLotsBS processing step with autocommit restore. Item updates now flow: stage → InsertLotsBS → WP post + meta → cache clear. - Worker spawn reliability — Changed
SyncQueue::spawnWorker()from non-blocking HTTPS to blocking HTTP loopback (http://127.0.0.1with explicitHostheader, 2s timeout). Fixes nginx 403/404 errors when HTTPS loopback hits the default vhost instead of the site's vhost. - API token constant — Plugin expects
AUCTIONFORGE_API_TOKENinwp-config.php(renamed fromUCO_API_TOKENduring the plugin rename). Documented in readme.
Database
- DB version: 22 → 23
Files Changed
- Modified:
inc/controllers/AuctionsAPI.php,inc/sync/ItemUpdateWorker.php,inc/sync/SyncQueue.php,auctionforge.php,admin/view/sync-status.php,readme.txt
---
[3.0.0] — 2025-03-14
New Feature: Webhook-First Sync Architecture (Sync v3)
Overview: Complete redesign of the BidSpirit data synchronisation pipeline. Replaces the old two-phase polling system (importBidSpirit every hour + importData every minute) with a webhook-driven job queue that processes data in near real-time.
Architecture
- 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: webhook → queue → background worker → WordPress posts. - Dual-write mode — During transition, webhooks enqueue jobs AND still run the legacy handlers. Once verified, legacy handlers can be removed cleanly.
- Job deduplication — Prevents duplicate work by checking for existing pending/processing jobs with the same auction_id + job_type.
New Components
- Job Queue System (
inc/sync/SyncQueue.php) — Priority-based FIFO queue with atomic job claiming, status tracking (pending/processing/completed/failed/skipped), worker PID tracking, and automatic stuck job recovery. - Sync Logger (
inc/sync/SyncLogger.php) — Real-time log table for admin console polling with level filtering (info/success/warning/error) and incremental cursor-based retrieval. - Catalog Sync Worker (
inc/sync/CatalogSyncWorker.php) — Processes catalog_sync, full_sync, and day_ended jobs by reusing existingLotList::singleRun()logic. - Item Update Worker (
inc/sync/ItemUpdateWorker.php) — Processes individual item_update jobs with the same logic as the webhookitemsUpdatedhandler. - Background Worker (
crontasks/syncWorker.php) — Async CLI process spawned by webhooks viaexec()or by the safety cron. Claims and processes queued jobs with a configurable timeout (default 240s). - Safety Net (
crontasks/syncSafety.php) — Hourly cron that resets stuck jobs (>10min), spawns workers for pending jobs, runs a 24-hour health check (auto-enqueues full sync if no webhooks received), and purges old data.
Admin UI
- Queue Status Dashboard — New card on Sync Status page showing pending/processing/completed/failed/skipped counts, recent jobs table with real-time refresh, worker status badge, and action buttons:
- Full Sync — Enqueues catalog sync for all active auctions
- Sync Selected — Enqueue a single auction from dropdown
- Spawn Worker — Manually trigger a background worker process
- Live Console — Dark-themed terminal console on the Sync Status page. Polls
af_sync_logevery 1.5s showing timestamped, color-coded log entries from webhooks, workers, queue operations, and the safety cron. Supports pause, clear, and auto-scroll.
Cron Changes
- Removed
importData(ran every minute — ~1,440 PHP executions/day) - Removed
importBidSpirit(ran hourly — ~24 PHP executions/day) - Added
syncSafety(runs hourly at :10 — 24 PHP executions/day) - Net effect: ~62 PHP executions/hour → 1 PHP execution/hour
- WP-Cron safety hook (
auctionforge_sync_safety) — Always-active hourly event, independent of external cron - setup.sh v3 — Updated task definitions, new
migratecommand for interactive v2→v3 transition
Database
- New table:
af_sync_queue— Job queue with status, priority, source, attempts, worker PID, timing columns - New table:
af_sync_log— Real-time log entries with context, level, auction_id, job_id - DB version: 20 → 22
Constants Added
| Constant | Default | Description |
|---|---|---|
|
AUCTIONFORGE_SYNC_WORKER_TIMEOUT| 240 | Worker process timeout in seconds ||
AUCTIONFORGE_SYNC_STALE_JOB| 600 | Seconds before a processing job is considered stuck ||
AUCTIONFORGE_SYNC_HEALTH_CHECK| 86400 | Seconds without webhook before triggering full sync ||
AUCTIONFORGE_SYNC_LOG_RETENTION| 7 | Days to keep log entries ||
AUCTIONFORGE_SYNC_QUEUE_RETENTION| 30 | Days to keep completed queue jobs ||
AUCTIONFORGE_CURL_TIMEOUT| 30 | BidSpirit API cURL timeout in seconds ||
AUCTIONFORGE_PHP_BINARY| /www/server/php/83/bin/php | PHP CLI binary path for spawning workers |AJAX Handlers Added
auctionforge_sync_log_poll— Incremental log polling for live consoleauctionforge_sync_queue_status— Queue counts + recent jobs for dashboardauctionforge_sync_enqueue— Admin-triggered sync actions (full_sync, sync_auction, spawn_worker)
Fixes
- cURL timeout — BidSpiritRequest now enforces a 30-second timeout (was unlimited/0), preventing hung connections from blocking the sync pipeline.
Files Changed
- Modified:
auctionforge.php,inc/coreIncludes.php,inc/controllers/AuctionsAPI.php,inc/BidSpiritRequest.php,admin/view/sync-status.php,crontasks/setup.sh - Created:
inc/sync/SyncQueue.php,inc/sync/SyncLogger.php,inc/sync/CatalogSyncWorker.php,inc/sync/ItemUpdateWorker.php,crontasks/syncWorker.php,crontasks/syncSafety.php
---
[2.7.3.0]
Fixes
- Various stability improvements and bug fixes.
[2.7.1.2]
Fixes
- Added missing
vatAndCommission()function inloadBid()— the sales tax display on single lot pages was never being rendered because the code to callloadTemplateforvat-and-commission-templatewas missing fromapp.js.
[2.7.1.1]
Fixes
- 2 decimal places now only appear in the bid modal (Your max bid, Total Price) via
showDecimalsflag. 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.
[2.7.0.9]
Fixes
- Fixed fatal error during plugin install/upgrade:
class-stats-database.phprequire failure.
[2.7.0.0]
New Features: Advanced Lot Analytics
- Conversion Tracking, Peak Viewing Times, Pre-Sale vs Live Comparison, Category Performance, Share Analytics, Search → View Funnel, Click-Through Tracking, CSV Export, Hot Lot Badge.
- New DB table:
af_lot_shares. New columns onaf_lot_analytics. DB version bumped to 20.
[2.6.0.0]
New Feature: Lot Analytics
- Comprehensive lot view and favorite tracking system with admin dashboard.
[2.5.0.0]
New Features
- Site Statistics System — Full website analytics built into the plugin admin.
- Recently Viewed Items — Profile page tab showing last 20 viewed lots per user.
- Namespace resolution — Fixed fatal error in
-
v3.6.0.12 Stable Apr 18, 2026Download v3.6.0.12📦 8.94 MB⚙️ WP 5.2+🔧 PHP 7.2+✓ Tested 6.4
AuctionForge Changelog
All notable changes to the AuctionForge plugin are documented in this file.
---
[3.6.0.7] — 2026-04-14
Hotfix
Fixes
- Namespace resolution — Fixed fatal error in
wp_footercommission label hook caused by unqualifiedSettingsHelperandSettingsclass references. Now uses fully qualified namespaces.
Files Changed
- Modified:
auctionforge.php
---
[3.6.0.6] — 2026-04-14
Commission Label Override Fix
Fixes
- Theme template override compatibility — Moved the commission label JS override from the
single-lot.phptemplate intoauctionforge.phpviawp_footerhook (priority 99). Sites with theme-level template overrides (e.g.themes/*/auctionforge/single-lot.php) were not picking up the inline script. Thewp_footerapproach works universally on all single lot pages.
Files Changed
- Modified:
auctionforge.php,templates/single-lot.php
---
[3.6.0.5] — 2026-04-14
Commission Label Override
Features
- Commission Label Setting — New dropdown in Settings → Appearance allowing admins to choose between "Buyer's Premium" (default) and "Auction House Commission" as the label displayed on lot pages. This overrides the Bidspirit JS client's default label using a MutationObserver that catches asynchronously injected text.
Files Changed
- Modified:
inc/controllers/Settings.php,templates/single-lot.php
---
[3.6.0.4] — 2026-04-12
Auction Approval Modal Redesign
Changes
- Removed BidSpirit Terms of Use — The generic BidSpirit "Terms of Use" section that appeared at the top of the non-credit-card approval modal has been removed. The modal now shows only the auction house's own legal agreements managed within the plugin.
- Renamed Modal Title — Changed "Terms of conditions" to "Terms & Conditions".
- Larger Scroll Area — The Terms & Conditions scroll box is now 350px tall (up from 200px) for easier reading.
- Proportional Section Heights — Refund & Return Policy and Chargeback Waiver sections use a shorter 260px scroll box to visually distinguish them from the primary Terms & Conditions.
Files Changed
- Modified:
templates/js-chunks/approval-info.php,assets/js/app.js
---
[3.6.0.2] — 2026-04-10
Webhook Token Generator
Features
- Token Generator Widget — Added a 16-character random token generator directly below the "Webhook auth token" field on the Settings page. Includes a "Generate Token" button and a clipboard copy icon with visual feedback.
Files Changed
- Modified:
inc/controllers/Settings.php
---
[3.6.0.1] — 2026-04-10
Patch
Changes
- Version bump.
---
[3.6.0.0] — 2026-04-10
Legal Agreements for Auction Approval
Features
- Terms & Conditions — A mandatory, scrollable Terms & Conditions document is now displayed during the auction approval process. Bidders must scroll to the bottom and check an agreement box before their approval request is submitted. Always enabled.
- Refund & Return Policy — An optional, scrollable Refund & Return Policy can be enabled in Settings. When enabled, bidders must read and accept it during auction approval.
- Chargeback Waiver — An optional, scrollable Chargeback Waiver can be enabled in Settings. When enabled, bidders must read and accept it during auction approval.
- Admin Management — New "Legal Agreements" page under the Bidspirit admin menu with tabbed TinyMCE editors for each agreement type. Includes automatic version numbering (incremented on content change) and full version history.
- Consent Logging — Every agreement acceptance is logged to a dedicated database table (
af_user_agreement_log) with the agreement type, version, user email, IP address, user agent, auction ID, and timestamp. - User Tracking Integration — Agreement events (
terms_agreement,refund_agreement,chargeback_waiver) are also recorded in the existing IP tracking system alongside registration, login, and bid events. - Placeholder Content — Default sample content is seeded on plugin activation for all three agreement types.
Settings Added
- Enable Refund & Return Policy — Toggle to require bidders to accept the refund policy during auction approval.
- Enable Chargeback Waiver — Toggle to require bidders to accept the chargeback waiver during auction approval.
Database
- New table:
af_legal_agreements— Current active agreement content per type - New table:
af_legal_agreement_versions— Version history archive - New table:
af_user_agreement_log— User consent records
Files Changed
- Modified:
auctionforge.php,inc/controllers/Settings.php,inc/controllers/BidspiritViews.php,inc/ip-logger.php,templates/js-chunks/approval-info.php,assets/js/app.js - Created:
inc/legal/class-legal-agreements.php,admin/view/legal-agreements.php
---
[3.5.0.6] — 2026-04-08
Bid Event Tracking
Features
- Bid Tracking — All successful bids (regular, catalog, pre-sale buyout, post-sale purchase) now fire
afLogIP("bid", bidspiritUser)to capture the bidder's full identity in the user tracking table. - Whitelist Update — Added
bidto the allowedevent_typevalues in both the local plugin and the central WPDeploy API.
---
[3.5.0.5] — 2026-04-08
Self-Healing Database Schema
Features
- Auto-Migration — The plugin now auto-detects and adds any missing tracking table columns on version upgrade, ensuring sites with older schemas seamlessly migrate without manual SQL.
---
[3.5.0.4] — 2026-04-08
API Key Auto-Healing
Features
- Seamless Self-Registration — The WordPress plugin now autonomously regenerates and saves a fresh API Key whenever WPDeploy rejects a payload with an
api_key_collisionerror. This guarantees zero-downtime security handovers when developers clone instances to proxy/staging servers.
---
[3.5.0.3] — 2026-04-08
API Key Collision Defense
Features
- 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_collisionerrors, directly instructing developers to update cloned keys.
---
[3.5.0.2] — 2026-04-08
Modal Trigger Hotfix
Fixes
- Restructured internal UI rendering priority to gracefully deploy the inline Modal triggers inside custom IP log view without colliding with cached
z-indexstacks.
---
[3.5.0.1] — 2026-04-08
Hotfix
Fixes
- Timed Auction Badge Visibility — Fixed a strict type-matching bug in the main
auction_list.phpcore file that incorrectly hid the "Timed Auction" badge overlay from valid timed/online auctions on the main upcoming/archive views. The badge now displays properly across all manual and Bidspirit-synced objects when toggled on.
Files Changed
- Modified:
templates/main/auction_list.php
---
[3.2.9.1] — 2026-03-30
Timed Auction Display Enhancements
Features
- Timed Auction Countdown Text Toggle — Added a WP-Admin setting "Change text to 'Auction will close in'" that conditionally changes the countdown label for timed/online auctions on single lot pages.
- Shortcode Text Toggle Support — Extended the new countdown text logic to the
bp_upcoming_wideshortcodes so "Live bidding starts in:" successfully transitions to "Auction will close in:" for timed auctions.
Files Changed
- Modified:
inc/controllers/Settings.php,templates/single-lot.php,templates/shortcodes/upcoming-auction-wide.php,templates/shortcodes/upcoming-auction-wide-manual.php
---
[3.2.9.0] — 2026-03-29
Billing & Invoices Polish
Fixes
- Profile Invoice ID Tracking — Prevented internal auction codes (e.g.
002orai4) from breaking into the clean hyphenated titles inside theprofile-templates.phpview. - Dynamic Payment Statuses — Replaced Bidspirit's default/cached
NOT PAIDHTML payloads by wiring thedompdfgenerator to directly respect the current$b.statusstring from the API (resolving instances where a paid invoice still printed "NOT PAID" atop the document). - Payment Instructions Conditional — Automatically hide the "Payment Instructions" block from the PDF footer when an invoice is fully paid.
- Improved Nomenclature — Changed "Invoice No:" to "Bidder No:" on document output to prevent confusion with static invoice ledger IDs.
---
[3.2.6.0] — 2026-03-28
Multi-Day Auction Lot Filtering Fix
Fixes
- Day 2+ showing lots from Day 1 in multi-day auctions — The
itemIndexcolumn inbp_meta_dataisvarchar(55), but the day-range filter inBidspiritQuery::bp_query_where()was comparing it as a string. With string comparison, lot numbers like'11','101'–'145'incorrectly fell between'1001'and'1450', causing Day 1 lots to leak into Day 2 results. Fixed by usingCAST(bpMeta.itemIndex AS UNSIGNED)for numeric comparison andintval()on the PHP-side boundary values. Letter lots (e.g.14A,1025A) are handled correctly —CASTstrips the suffix, keeping them grouped with their base lot number.
Files Changed
- Modified:
inc/controllers/BidspiritQuery.php
---
[3.2.5.9] — 2026-03-27
Catalog Page Fix
Fixes
- Duplicate preview hours on catalog pages — The
displayHoursfield was rendered twice: once via thebp_after_description_auctionhook inBidspiritViews.phpand once inline in the auction template. Removed the hook-based rendering to eliminate the duplication.
Files Changed
- Modified:
inc/controllers/BidspiritViews.php,templates/main/auction.php
---
[3.2.5] — 2026-03-19
Sync Reliability & Stuck Lot Prevention
Fixes
- CATALOG_PUBLISHED webhook now triggers catalog sync — Previously only sent push notifications without syncing lots. When the earlier AUCTION_CATALOG_UPDATED fired before the catalog was ready on BidSpirit, lots were never imported. CATALOG_PUBLISHED now calls
auctionCatalogUpdated()to trigger a full catalog sync when the catalog is actually available. - 0-lot API results now fail instead of silently succeeding — When BidSpirit API returns 0 lots (catalog not yet ready), the sync job now fails with an explicit error message, allowing the next webhook to create a fresh retry job.
- Expanded CDN allowlist in pre_http_request filter — The HTTP filter during bulk post insertion now allows all
*.bidspirit.comsubdomains and BidSpirit image CDNs (fastly.net,cloudfront.net). Previously onlybidspirit.comandwww.bidspirit.comwere allowed, blocking image downloads during sync and causing worker hangs. - InsertLotsBS timeout guard — Stage 5 (InsertLotsBS processing loop) now has a 180-second timeout and logs progress every 2 batches. Prevents indefinite hangs that previously required manual force-kill.
- fixResult() no longer marks lots as done when postId=0 — When
lotProcessing()fails to create a WP post, the staging row now keepssyncFinished=0so the lot is retried on the next sync pass, instead of being permanently marked as complete with no actual post. - lotProcessing() logs error on missing auction term — Previously returned 0 silently when
Auction::findAuctionById()failed. Now logs an explicit error that feeds intofixResult()to keep the lot retryable. - Hourly orphan detection in safety cron — New step in
syncSafety.phpdetects lot posts that exist inbp_meta_databut are missing their auction taxonomy assignment (caused by workers killed mid-batch) and auto-repairs them withwp_set_object_terms().
Files Changed
- Modified:
inc/controllers/AuctionsAPI.php,inc/sync/CatalogSyncWorker.php,inc/abs/InsertLotsAbstract.php,inc/import/InsertLotsBS.php,crontasks/syncSafety.php
---
[3.2.4] — 2026-03-18
Sync Worker Hang Fix
Fixes
- Sync workers hanging at InsertLotsBS stage — Third-party plugins (Smush Pro, SmartCrawl SEO, WPMU DEV Updates) hook into
wp_insert_post()and make blocking outbound HTTPS calls for every lot processed. With 489+ lots per auction, this caused workers to hang indefinitely on socket reads to WPMU DEV servers (32.193.94.25,32.193.93.106). AddedWP_IMPORTINGconstant at the REST worker entry point and apre_http_requestfilter inCatalogSyncWorkerthat blocks all non-essential external HTTP during the batch post-insertion phase. Loopback (127.0.0.1,localhost) and BidSpirit API calls remain allowed. - Stuck staging rows after force-kill — When workers were force-killed mid-sync, staging rows in
import_historywere left withsyncstart=1and never unblocked. Subsequent sync runs could not see these rows (filtered out byLot::getRawLots()), causing the InsertLotsBS loop to exit immediately with 0 posts processed. Combined with job deduplication (SyncQueue::enqueue()skips if aprocessingjob exists), this created a deadlock where no new sync could proceed.
Files Changed
- Modified:
auctionforge.php,inc/sync/CatalogSyncWorker.php
---
[3.2.2] — 2026-03-17
Full Sync Auction Discovery Fix
Fixes
- Full Sync finds no auctions on fresh sites — The v3
full_syncaction only queried the WordPress database for existing auction terms, but on a freshly deployed site the database has zero auctions. AddedAuctionList::init()discovery step before querying the DB, so Full Sync now fetches all auctions from the BidSpirit API and creates taxonomy terms first, then enqueues catalog sync jobs for each.
Files Changed
- Modified:
auctionforge.php
---
[3.2.0] — 2026-03-14
Webhook Pipeline Fixes, Archive Sync & Admin UI Overhaul
New Features
- Archive Sync — New "Archive Sync" button on Sync Status admin page. Enqueues catalog sync jobs for all ARCHIVED/ENDED auctions. Past auctions now appear in the auction dropdown with an optgroup separator and state label.
- Sync Tasks v3 — Replaced old v2 task cards (importData, importBidSpirit, lotBidSpiritOld) with v3 queue-based tasks. "Sync Active Auctions" and "Sync Archived Auctions" now enqueue jobs via the queue system. Maintenance tasks (Clean Draft/Trash Lots, Clean Orphaned Meta) remain as direct-execution tasks.
- How It Works guide rewritten — Complete rewrite of the admin guide for v3 architecture. Documents webhook-first flow, all 5 job types, queue system mechanics, cron setup (external + WP-Cron), configuration constants, and troubleshooting.
Fixes
- Dual-write removed — Removed legacy handlers from
auctionCatalogUpdated(),auctionDayEnded(), anditemsUpdated()webhook methods. The old handlers were racing with the v3 worker, creating orphaned staging rows inimport_historythat were never processed. All three methods now exclusively use the v3 enqueue → spawn path. - ITEMS_UPDATED webhook — Fixed
itemsUpdated()failing to enqueue jobs. TheITEMS_UPDATEDpayload hasauctionIdnested initemsByLanguage.{lang}[0].item.auctionId, not at the top level. Added extraction logic to resolve it. - ItemUpdateWorker incomplete —
ItemUpdateWorker::process()was only callingLot::bulkSave()(staging table) without runningInsertLotsBSto process staged data into WP posts andbp_meta_data. Added the InsertLotsBS processing step with autocommit restore. Item updates now flow: stage → InsertLotsBS → WP post + meta → cache clear. - Worker spawn reliability — Changed
SyncQueue::spawnWorker()from non-blocking HTTPS to blocking HTTP loopback (http://127.0.0.1with explicitHostheader, 2s timeout). Fixes nginx 403/404 errors when HTTPS loopback hits the default vhost instead of the site's vhost. - API token constant — Plugin expects
AUCTIONFORGE_API_TOKENinwp-config.php(renamed fromUCO_API_TOKENduring the plugin rename). Documented in readme.
Database
- DB version: 22 → 23
Files Changed
- Modified:
inc/controllers/AuctionsAPI.php,inc/sync/ItemUpdateWorker.php,inc/sync/SyncQueue.php,auctionforge.php,admin/view/sync-status.php,readme.txt
---
[3.0.0] — 2025-03-14
New Feature: Webhook-First Sync Architecture (Sync v3)
Overview: Complete redesign of the BidSpirit data synchronisation pipeline. Replaces the old two-phase polling system (importBidSpirit every hour + importData every minute) with a webhook-driven job queue that processes data in near real-time.
Architecture
- 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: webhook → queue → background worker → WordPress posts. - Dual-write mode — During transition, webhooks enqueue jobs AND still run the legacy handlers. Once verified, legacy handlers can be removed cleanly.
- Job deduplication — Prevents duplicate work by checking for existing pending/processing jobs with the same auction_id + job_type.
New Components
- Job Queue System (
inc/sync/SyncQueue.php) — Priority-based FIFO queue with atomic job claiming, status tracking (pending/processing/completed/failed/skipped), worker PID tracking, and automatic stuck job recovery. - Sync Logger (
inc/sync/SyncLogger.php) — Real-time log table for admin console polling with level filtering (info/success/warning/error) and incremental cursor-based retrieval. - Catalog Sync Worker (
inc/sync/CatalogSyncWorker.php) — Processes catalog_sync, full_sync, and day_ended jobs by reusing existingLotList::singleRun()logic. - Item Update Worker (
inc/sync/ItemUpdateWorker.php) — Processes individual item_update jobs with the same logic as the webhookitemsUpdatedhandler. - Background Worker (
crontasks/syncWorker.php) — Async CLI process spawned by webhooks viaexec()or by the safety cron. Claims and processes queued jobs with a configurable timeout (default 240s). - Safety Net (
crontasks/syncSafety.php) — Hourly cron that resets stuck jobs (>10min), spawns workers for pending jobs, runs a 24-hour health check (auto-enqueues full sync if no webhooks received), and purges old data.
Admin UI
- Queue Status Dashboard — New card on Sync Status page showing pending/processing/completed/failed/skipped counts, recent jobs table with real-time refresh, worker status badge, and action buttons:
- Full Sync — Enqueues catalog sync for all active auctions
- Sync Selected — Enqueue a single auction from dropdown
- Spawn Worker — Manually trigger a background worker process
- Live Console — Dark-themed terminal console on the Sync Status page. Polls
af_sync_logevery 1.5s showing timestamped, color-coded log entries from webhooks, workers, queue operations, and the safety cron. Supports pause, clear, and auto-scroll.
Cron Changes
- Removed
importData(ran every minute — ~1,440 PHP executions/day) - Removed
importBidSpirit(ran hourly — ~24 PHP executions/day) - Added
syncSafety(runs hourly at :10 — 24 PHP executions/day) - Net effect: ~62 PHP executions/hour → 1 PHP execution/hour
- WP-Cron safety hook (
auctionforge_sync_safety) — Always-active hourly event, independent of external cron - setup.sh v3 — Updated task definitions, new
migratecommand for interactive v2→v3 transition
Database
- New table:
af_sync_queue— Job queue with status, priority, source, attempts, worker PID, timing columns - New table:
af_sync_log— Real-time log entries with context, level, auction_id, job_id - DB version: 20 → 22
Constants Added
| Constant | Default | Description |
|---|---|---|
|
AUCTIONFORGE_SYNC_WORKER_TIMEOUT| 240 | Worker process timeout in seconds ||
AUCTIONFORGE_SYNC_STALE_JOB| 600 | Seconds before a processing job is considered stuck ||
AUCTIONFORGE_SYNC_HEALTH_CHECK| 86400 | Seconds without webhook before triggering full sync ||
AUCTIONFORGE_SYNC_LOG_RETENTION| 7 | Days to keep log entries ||
AUCTIONFORGE_SYNC_QUEUE_RETENTION| 30 | Days to keep completed queue jobs ||
AUCTIONFORGE_CURL_TIMEOUT| 30 | BidSpirit API cURL timeout in seconds ||
AUCTIONFORGE_PHP_BINARY| /www/server/php/83/bin/php | PHP CLI binary path for spawning workers |AJAX Handlers Added
auctionforge_sync_log_poll— Incremental log polling for live consoleauctionforge_sync_queue_status— Queue counts + recent jobs for dashboardauctionforge_sync_enqueue— Admin-triggered sync actions (full_sync, sync_auction, spawn_worker)
Fixes
- cURL timeout — BidSpiritRequest now enforces a 30-second timeout (was unlimited/0), preventing hung connections from blocking the sync pipeline.
Files Changed
- Modified:
auctionforge.php,inc/coreIncludes.php,inc/controllers/AuctionsAPI.php,inc/BidSpiritRequest.php,admin/view/sync-status.php,crontasks/setup.sh - Created:
inc/sync/SyncQueue.php,inc/sync/SyncLogger.php,inc/sync/CatalogSyncWorker.php,inc/sync/ItemUpdateWorker.php,crontasks/syncWorker.php,crontasks/syncSafety.php
---
[2.7.3.0]
Fixes
- Various stability improvements and bug fixes.
[2.7.1.2]
Fixes
- Added missing
vatAndCommission()function inloadBid()— the sales tax display on single lot pages was never being rendered because the code to callloadTemplateforvat-and-commission-templatewas missing fromapp.js.
[2.7.1.1]
Fixes
- 2 decimal places now only appear in the bid modal (Your max bid, Total Price) via
showDecimalsflag. 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.
[2.7.0.9]
Fixes
- Fixed fatal error during plugin install/upgrade:
class-stats-database.phprequire failure.
[2.7.0.0]
New Features: Advanced Lot Analytics
- Conversion Tracking, Peak Viewing Times, Pre-Sale vs Live Comparison, Category Performance, Share Analytics, Search → View Funnel, Click-Through Tracking, CSV Export, Hot Lot Badge.
- New DB table:
af_lot_shares. New columns onaf_lot_analytics. DB version bumped to 20.
[2.6.0.0]
New Feature: Lot Analytics
- Comprehensive lot view and favorite tracking system with admin dashboard.
[2.5.0.0]
New Features
- Site Statistics System — Full website analytics built into the plugin admin.
- Recently Viewed Items — Profile page tab showing last 20 viewed lots per user.
- Namespace resolution — Fixed fatal error in
-
v3.6.0.10 Stable Apr 15, 2026Download v3.6.0.10📦 8.93 MB⚙️ WP 5.2+🔧 PHP 7.2+✓ Tested 6.4
AuctionForge Changelog
All notable changes to the AuctionForge plugin are documented in this file.
---
[3.6.0.7] — 2026-04-14
Hotfix
Fixes
- Namespace resolution — Fixed fatal error in
wp_footercommission label hook caused by unqualifiedSettingsHelperandSettingsclass references. Now uses fully qualified namespaces.
Files Changed
- Modified:
auctionforge.php
---
[3.6.0.6] — 2026-04-14
Commission Label Override Fix
Fixes
- Theme template override compatibility — Moved the commission label JS override from the
single-lot.phptemplate intoauctionforge.phpviawp_footerhook (priority 99). Sites with theme-level template overrides (e.g.themes/*/auctionforge/single-lot.php) were not picking up the inline script. Thewp_footerapproach works universally on all single lot pages.
Files Changed
- Modified:
auctionforge.php,templates/single-lot.php
---
[3.6.0.5] — 2026-04-14
Commission Label Override
Features
- Commission Label Setting — New dropdown in Settings → Appearance allowing admins to choose between "Buyer's Premium" (default) and "Auction House Commission" as the label displayed on lot pages. This overrides the Bidspirit JS client's default label using a MutationObserver that catches asynchronously injected text.
Files Changed
- Modified:
inc/controllers/Settings.php,templates/single-lot.php
---
[3.6.0.4] — 2026-04-12
Auction Approval Modal Redesign
Changes
- Removed BidSpirit Terms of Use — The generic BidSpirit "Terms of Use" section that appeared at the top of the non-credit-card approval modal has been removed. The modal now shows only the auction house's own legal agreements managed within the plugin.
- Renamed Modal Title — Changed "Terms of conditions" to "Terms & Conditions".
- Larger Scroll Area — The Terms & Conditions scroll box is now 350px tall (up from 200px) for easier reading.
- Proportional Section Heights — Refund & Return Policy and Chargeback Waiver sections use a shorter 260px scroll box to visually distinguish them from the primary Terms & Conditions.
Files Changed
- Modified:
templates/js-chunks/approval-info.php,assets/js/app.js
---
[3.6.0.2] — 2026-04-10
Webhook Token Generator
Features
- Token Generator Widget — Added a 16-character random token generator directly below the "Webhook auth token" field on the Settings page. Includes a "Generate Token" button and a clipboard copy icon with visual feedback.
Files Changed
- Modified:
inc/controllers/Settings.php
---
[3.6.0.1] — 2026-04-10
Patch
Changes
- Version bump.
---
[3.6.0.0] — 2026-04-10
Legal Agreements for Auction Approval
Features
- Terms & Conditions — A mandatory, scrollable Terms & Conditions document is now displayed during the auction approval process. Bidders must scroll to the bottom and check an agreement box before their approval request is submitted. Always enabled.
- Refund & Return Policy — An optional, scrollable Refund & Return Policy can be enabled in Settings. When enabled, bidders must read and accept it during auction approval.
- Chargeback Waiver — An optional, scrollable Chargeback Waiver can be enabled in Settings. When enabled, bidders must read and accept it during auction approval.
- Admin Management — New "Legal Agreements" page under the Bidspirit admin menu with tabbed TinyMCE editors for each agreement type. Includes automatic version numbering (incremented on content change) and full version history.
- Consent Logging — Every agreement acceptance is logged to a dedicated database table (
af_user_agreement_log) with the agreement type, version, user email, IP address, user agent, auction ID, and timestamp. - User Tracking Integration — Agreement events (
terms_agreement,refund_agreement,chargeback_waiver) are also recorded in the existing IP tracking system alongside registration, login, and bid events. - Placeholder Content — Default sample content is seeded on plugin activation for all three agreement types.
Settings Added
- Enable Refund & Return Policy — Toggle to require bidders to accept the refund policy during auction approval.
- Enable Chargeback Waiver — Toggle to require bidders to accept the chargeback waiver during auction approval.
Database
- New table:
af_legal_agreements— Current active agreement content per type - New table:
af_legal_agreement_versions— Version history archive - New table:
af_user_agreement_log— User consent records
Files Changed
- Modified:
auctionforge.php,inc/controllers/Settings.php,inc/controllers/BidspiritViews.php,inc/ip-logger.php,templates/js-chunks/approval-info.php,assets/js/app.js - Created:
inc/legal/class-legal-agreements.php,admin/view/legal-agreements.php
---
[3.5.0.6] — 2026-04-08
Bid Event Tracking
Features
- Bid Tracking — All successful bids (regular, catalog, pre-sale buyout, post-sale purchase) now fire
afLogIP("bid", bidspiritUser)to capture the bidder's full identity in the user tracking table. - Whitelist Update — Added
bidto the allowedevent_typevalues in both the local plugin and the central WPDeploy API.
---
[3.5.0.5] — 2026-04-08
Self-Healing Database Schema
Features
- Auto-Migration — The plugin now auto-detects and adds any missing tracking table columns on version upgrade, ensuring sites with older schemas seamlessly migrate without manual SQL.
---
[3.5.0.4] — 2026-04-08
API Key Auto-Healing
Features
- Seamless Self-Registration — The WordPress plugin now autonomously regenerates and saves a fresh API Key whenever WPDeploy rejects a payload with an
api_key_collisionerror. This guarantees zero-downtime security handovers when developers clone instances to proxy/staging servers.
---
[3.5.0.3] — 2026-04-08
API Key Collision Defense
Features
- 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_collisionerrors, directly instructing developers to update cloned keys.
---
[3.5.0.2] — 2026-04-08
Modal Trigger Hotfix
Fixes
- Restructured internal UI rendering priority to gracefully deploy the inline Modal triggers inside custom IP log view without colliding with cached
z-indexstacks.
---
[3.5.0.1] — 2026-04-08
Hotfix
Fixes
- Timed Auction Badge Visibility — Fixed a strict type-matching bug in the main
auction_list.phpcore file that incorrectly hid the "Timed Auction" badge overlay from valid timed/online auctions on the main upcoming/archive views. The badge now displays properly across all manual and Bidspirit-synced objects when toggled on.
Files Changed
- Modified:
templates/main/auction_list.php
---
[3.2.9.1] — 2026-03-30
Timed Auction Display Enhancements
Features
- Timed Auction Countdown Text Toggle — Added a WP-Admin setting "Change text to 'Auction will close in'" that conditionally changes the countdown label for timed/online auctions on single lot pages.
- Shortcode Text Toggle Support — Extended the new countdown text logic to the
bp_upcoming_wideshortcodes so "Live bidding starts in:" successfully transitions to "Auction will close in:" for timed auctions.
Files Changed
- Modified:
inc/controllers/Settings.php,templates/single-lot.php,templates/shortcodes/upcoming-auction-wide.php,templates/shortcodes/upcoming-auction-wide-manual.php
---
[3.2.9.0] — 2026-03-29
Billing & Invoices Polish
Fixes
- Profile Invoice ID Tracking — Prevented internal auction codes (e.g.
002orai4) from breaking into the clean hyphenated titles inside theprofile-templates.phpview. - Dynamic Payment Statuses — Replaced Bidspirit's default/cached
NOT PAIDHTML payloads by wiring thedompdfgenerator to directly respect the current$b.statusstring from the API (resolving instances where a paid invoice still printed "NOT PAID" atop the document). - Payment Instructions Conditional — Automatically hide the "Payment Instructions" block from the PDF footer when an invoice is fully paid.
- Improved Nomenclature — Changed "Invoice No:" to "Bidder No:" on document output to prevent confusion with static invoice ledger IDs.
---
[3.2.6.0] — 2026-03-28
Multi-Day Auction Lot Filtering Fix
Fixes
- Day 2+ showing lots from Day 1 in multi-day auctions — The
itemIndexcolumn inbp_meta_dataisvarchar(55), but the day-range filter inBidspiritQuery::bp_query_where()was comparing it as a string. With string comparison, lot numbers like'11','101'–'145'incorrectly fell between'1001'and'1450', causing Day 1 lots to leak into Day 2 results. Fixed by usingCAST(bpMeta.itemIndex AS UNSIGNED)for numeric comparison andintval()on the PHP-side boundary values. Letter lots (e.g.14A,1025A) are handled correctly —CASTstrips the suffix, keeping them grouped with their base lot number.
Files Changed
- Modified:
inc/controllers/BidspiritQuery.php
---
[3.2.5.9] — 2026-03-27
Catalog Page Fix
Fixes
- Duplicate preview hours on catalog pages — The
displayHoursfield was rendered twice: once via thebp_after_description_auctionhook inBidspiritViews.phpand once inline in the auction template. Removed the hook-based rendering to eliminate the duplication.
Files Changed
- Modified:
inc/controllers/BidspiritViews.php,templates/main/auction.php
---
[3.2.5] — 2026-03-19
Sync Reliability & Stuck Lot Prevention
Fixes
- CATALOG_PUBLISHED webhook now triggers catalog sync — Previously only sent push notifications without syncing lots. When the earlier AUCTION_CATALOG_UPDATED fired before the catalog was ready on BidSpirit, lots were never imported. CATALOG_PUBLISHED now calls
auctionCatalogUpdated()to trigger a full catalog sync when the catalog is actually available. - 0-lot API results now fail instead of silently succeeding — When BidSpirit API returns 0 lots (catalog not yet ready), the sync job now fails with an explicit error message, allowing the next webhook to create a fresh retry job.
- Expanded CDN allowlist in pre_http_request filter — The HTTP filter during bulk post insertion now allows all
*.bidspirit.comsubdomains and BidSpirit image CDNs (fastly.net,cloudfront.net). Previously onlybidspirit.comandwww.bidspirit.comwere allowed, blocking image downloads during sync and causing worker hangs. - InsertLotsBS timeout guard — Stage 5 (InsertLotsBS processing loop) now has a 180-second timeout and logs progress every 2 batches. Prevents indefinite hangs that previously required manual force-kill.
- fixResult() no longer marks lots as done when postId=0 — When
lotProcessing()fails to create a WP post, the staging row now keepssyncFinished=0so the lot is retried on the next sync pass, instead of being permanently marked as complete with no actual post. - lotProcessing() logs error on missing auction term — Previously returned 0 silently when
Auction::findAuctionById()failed. Now logs an explicit error that feeds intofixResult()to keep the lot retryable. - Hourly orphan detection in safety cron — New step in
syncSafety.phpdetects lot posts that exist inbp_meta_databut are missing their auction taxonomy assignment (caused by workers killed mid-batch) and auto-repairs them withwp_set_object_terms().
Files Changed
- Modified:
inc/controllers/AuctionsAPI.php,inc/sync/CatalogSyncWorker.php,inc/abs/InsertLotsAbstract.php,inc/import/InsertLotsBS.php,crontasks/syncSafety.php
---
[3.2.4] — 2026-03-18
Sync Worker Hang Fix
Fixes
- Sync workers hanging at InsertLotsBS stage — Third-party plugins (Smush Pro, SmartCrawl SEO, WPMU DEV Updates) hook into
wp_insert_post()and make blocking outbound HTTPS calls for every lot processed. With 489+ lots per auction, this caused workers to hang indefinitely on socket reads to WPMU DEV servers (32.193.94.25,32.193.93.106). AddedWP_IMPORTINGconstant at the REST worker entry point and apre_http_requestfilter inCatalogSyncWorkerthat blocks all non-essential external HTTP during the batch post-insertion phase. Loopback (127.0.0.1,localhost) and BidSpirit API calls remain allowed. - Stuck staging rows after force-kill — When workers were force-killed mid-sync, staging rows in
import_historywere left withsyncstart=1and never unblocked. Subsequent sync runs could not see these rows (filtered out byLot::getRawLots()), causing the InsertLotsBS loop to exit immediately with 0 posts processed. Combined with job deduplication (SyncQueue::enqueue()skips if aprocessingjob exists), this created a deadlock where no new sync could proceed.
Files Changed
- Modified:
auctionforge.php,inc/sync/CatalogSyncWorker.php
---
[3.2.2] — 2026-03-17
Full Sync Auction Discovery Fix
Fixes
- Full Sync finds no auctions on fresh sites — The v3
full_syncaction only queried the WordPress database for existing auction terms, but on a freshly deployed site the database has zero auctions. AddedAuctionList::init()discovery step before querying the DB, so Full Sync now fetches all auctions from the BidSpirit API and creates taxonomy terms first, then enqueues catalog sync jobs for each.
Files Changed
- Modified:
auctionforge.php
---
[3.2.0] — 2026-03-14
Webhook Pipeline Fixes, Archive Sync & Admin UI Overhaul
New Features
- Archive Sync — New "Archive Sync" button on Sync Status admin page. Enqueues catalog sync jobs for all ARCHIVED/ENDED auctions. Past auctions now appear in the auction dropdown with an optgroup separator and state label.
- Sync Tasks v3 — Replaced old v2 task cards (importData, importBidSpirit, lotBidSpiritOld) with v3 queue-based tasks. "Sync Active Auctions" and "Sync Archived Auctions" now enqueue jobs via the queue system. Maintenance tasks (Clean Draft/Trash Lots, Clean Orphaned Meta) remain as direct-execution tasks.
- How It Works guide rewritten — Complete rewrite of the admin guide for v3 architecture. Documents webhook-first flow, all 5 job types, queue system mechanics, cron setup (external + WP-Cron), configuration constants, and troubleshooting.
Fixes
- Dual-write removed — Removed legacy handlers from
auctionCatalogUpdated(),auctionDayEnded(), anditemsUpdated()webhook methods. The old handlers were racing with the v3 worker, creating orphaned staging rows inimport_historythat were never processed. All three methods now exclusively use the v3 enqueue → spawn path. - ITEMS_UPDATED webhook — Fixed
itemsUpdated()failing to enqueue jobs. TheITEMS_UPDATEDpayload hasauctionIdnested initemsByLanguage.{lang}[0].item.auctionId, not at the top level. Added extraction logic to resolve it. - ItemUpdateWorker incomplete —
ItemUpdateWorker::process()was only callingLot::bulkSave()(staging table) without runningInsertLotsBSto process staged data into WP posts andbp_meta_data. Added the InsertLotsBS processing step with autocommit restore. Item updates now flow: stage → InsertLotsBS → WP post + meta → cache clear. - Worker spawn reliability — Changed
SyncQueue::spawnWorker()from non-blocking HTTPS to blocking HTTP loopback (http://127.0.0.1with explicitHostheader, 2s timeout). Fixes nginx 403/404 errors when HTTPS loopback hits the default vhost instead of the site's vhost. - API token constant — Plugin expects
AUCTIONFORGE_API_TOKENinwp-config.php(renamed fromUCO_API_TOKENduring the plugin rename). Documented in readme.
Database
- DB version: 22 → 23
Files Changed
- Modified:
inc/controllers/AuctionsAPI.php,inc/sync/ItemUpdateWorker.php,inc/sync/SyncQueue.php,auctionforge.php,admin/view/sync-status.php,readme.txt
---
[3.0.0] — 2025-03-14
New Feature: Webhook-First Sync Architecture (Sync v3)
Overview: Complete redesign of the BidSpirit data synchronisation pipeline. Replaces the old two-phase polling system (importBidSpirit every hour + importData every minute) with a webhook-driven job queue that processes data in near real-time.
Architecture
- 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: webhook → queue → background worker → WordPress posts. - Dual-write mode — During transition, webhooks enqueue jobs AND still run the legacy handlers. Once verified, legacy handlers can be removed cleanly.
- Job deduplication — Prevents duplicate work by checking for existing pending/processing jobs with the same auction_id + job_type.
New Components
- Job Queue System (
inc/sync/SyncQueue.php) — Priority-based FIFO queue with atomic job claiming, status tracking (pending/processing/completed/failed/skipped), worker PID tracking, and automatic stuck job recovery. - Sync Logger (
inc/sync/SyncLogger.php) — Real-time log table for admin console polling with level filtering (info/success/warning/error) and incremental cursor-based retrieval. - Catalog Sync Worker (
inc/sync/CatalogSyncWorker.php) — Processes catalog_sync, full_sync, and day_ended jobs by reusing existingLotList::singleRun()logic. - Item Update Worker (
inc/sync/ItemUpdateWorker.php) — Processes individual item_update jobs with the same logic as the webhookitemsUpdatedhandler. - Background Worker (
crontasks/syncWorker.php) — Async CLI process spawned by webhooks viaexec()or by the safety cron. Claims and processes queued jobs with a configurable timeout (default 240s). - Safety Net (
crontasks/syncSafety.php) — Hourly cron that resets stuck jobs (>10min), spawns workers for pending jobs, runs a 24-hour health check (auto-enqueues full sync if no webhooks received), and purges old data.
Admin UI
- Queue Status Dashboard — New card on Sync Status page showing pending/processing/completed/failed/skipped counts, recent jobs table with real-time refresh, worker status badge, and action buttons:
- Full Sync — Enqueues catalog sync for all active auctions
- Sync Selected — Enqueue a single auction from dropdown
- Spawn Worker — Manually trigger a background worker process
- Live Console — Dark-themed terminal console on the Sync Status page. Polls
af_sync_logevery 1.5s showing timestamped, color-coded log entries from webhooks, workers, queue operations, and the safety cron. Supports pause, clear, and auto-scroll.
Cron Changes
- Removed
importData(ran every minute — ~1,440 PHP executions/day) - Removed
importBidSpirit(ran hourly — ~24 PHP executions/day) - Added
syncSafety(runs hourly at :10 — 24 PHP executions/day) - Net effect: ~62 PHP executions/hour → 1 PHP execution/hour
- WP-Cron safety hook (
auctionforge_sync_safety) — Always-active hourly event, independent of external cron - setup.sh v3 — Updated task definitions, new
migratecommand for interactive v2→v3 transition
Database
- New table:
af_sync_queue— Job queue with status, priority, source, attempts, worker PID, timing columns - New table:
af_sync_log— Real-time log entries with context, level, auction_id, job_id - DB version: 20 → 22
Constants Added
| Constant | Default | Description |
|---|---|---|
|
AUCTIONFORGE_SYNC_WORKER_TIMEOUT| 240 | Worker process timeout in seconds ||
AUCTIONFORGE_SYNC_STALE_JOB| 600 | Seconds before a processing job is considered stuck ||
AUCTIONFORGE_SYNC_HEALTH_CHECK| 86400 | Seconds without webhook before triggering full sync ||
AUCTIONFORGE_SYNC_LOG_RETENTION| 7 | Days to keep log entries ||
AUCTIONFORGE_SYNC_QUEUE_RETENTION| 30 | Days to keep completed queue jobs ||
AUCTIONFORGE_CURL_TIMEOUT| 30 | BidSpirit API cURL timeout in seconds ||
AUCTIONFORGE_PHP_BINARY| /www/server/php/83/bin/php | PHP CLI binary path for spawning workers |AJAX Handlers Added
auctionforge_sync_log_poll— Incremental log polling for live consoleauctionforge_sync_queue_status— Queue counts + recent jobs for dashboardauctionforge_sync_enqueue— Admin-triggered sync actions (full_sync, sync_auction, spawn_worker)
Fixes
- cURL timeout — BidSpiritRequest now enforces a 30-second timeout (was unlimited/0), preventing hung connections from blocking the sync pipeline.
Files Changed
- Modified:
auctionforge.php,inc/coreIncludes.php,inc/controllers/AuctionsAPI.php,inc/BidSpiritRequest.php,admin/view/sync-status.php,crontasks/setup.sh - Created:
inc/sync/SyncQueue.php,inc/sync/SyncLogger.php,inc/sync/CatalogSyncWorker.php,inc/sync/ItemUpdateWorker.php,crontasks/syncWorker.php,crontasks/syncSafety.php
---
[2.7.3.0]
Fixes
- Various stability improvements and bug fixes.
[2.7.1.2]
Fixes
- Added missing
vatAndCommission()function inloadBid()— the sales tax display on single lot pages was never being rendered because the code to callloadTemplateforvat-and-commission-templatewas missing fromapp.js.
[2.7.1.1]
Fixes
- 2 decimal places now only appear in the bid modal (Your max bid, Total Price) via
showDecimalsflag. 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.
[2.7.0.9]
Fixes
- Fixed fatal error during plugin install/upgrade:
class-stats-database.phprequire failure.
[2.7.0.0]
New Features: Advanced Lot Analytics
- Conversion Tracking, Peak Viewing Times, Pre-Sale vs Live Comparison, Category Performance, Share Analytics, Search → View Funnel, Click-Through Tracking, CSV Export, Hot Lot Badge.
- New DB table:
af_lot_shares. New columns onaf_lot_analytics. DB version bumped to 20.
[2.6.0.0]
New Feature: Lot Analytics
- Comprehensive lot view and favorite tracking system with admin dashboard.
[2.5.0.0]
New Features
- Site Statistics System — Full website analytics built into the plugin admin.
- Recently Viewed Items — Profile page tab showing last 20 viewed lots per user.
- Namespace resolution — Fixed fatal error in
-
v3.6.0.8 Stable Apr 14, 2026Download v3.6.0.8📦 8.93 MB⚙️ WP 5.2+🔧 PHP 7.2+✓ Tested 6.4
AuctionForge Changelog
All notable changes to the AuctionForge plugin are documented in this file.
---
[3.6.0.7] — 2026-04-14
Hotfix
Fixes
- Namespace resolution — Fixed fatal error in
wp_footercommission label hook caused by unqualifiedSettingsHelperandSettingsclass references. Now uses fully qualified namespaces.
Files Changed
- Modified:
auctionforge.php
---
[3.6.0.6] — 2026-04-14
Commission Label Override Fix
Fixes
- Theme template override compatibility — Moved the commission label JS override from the
single-lot.phptemplate intoauctionforge.phpviawp_footerhook (priority 99). Sites with theme-level template overrides (e.g.themes/*/auctionforge/single-lot.php) were not picking up the inline script. Thewp_footerapproach works universally on all single lot pages.
Files Changed
- Modified:
auctionforge.php,templates/single-lot.php
---
[3.6.0.5] — 2026-04-14
Commission Label Override
Features
- Commission Label Setting — New dropdown in Settings → Appearance allowing admins to choose between "Buyer's Premium" (default) and "Auction House Commission" as the label displayed on lot pages. This overrides the Bidspirit JS client's default label using a MutationObserver that catches asynchronously injected text.
Files Changed
- Modified:
inc/controllers/Settings.php,templates/single-lot.php
---
[3.6.0.4] — 2026-04-12
Auction Approval Modal Redesign
Changes
- Removed BidSpirit Terms of Use — The generic BidSpirit "Terms of Use" section that appeared at the top of the non-credit-card approval modal has been removed. The modal now shows only the auction house's own legal agreements managed within the plugin.
- Renamed Modal Title — Changed "Terms of conditions" to "Terms & Conditions".
- Larger Scroll Area — The Terms & Conditions scroll box is now 350px tall (up from 200px) for easier reading.
- Proportional Section Heights — Refund & Return Policy and Chargeback Waiver sections use a shorter 260px scroll box to visually distinguish them from the primary Terms & Conditions.
Files Changed
- Modified:
templates/js-chunks/approval-info.php,assets/js/app.js
---
[3.6.0.2] — 2026-04-10
Webhook Token Generator
Features
- Token Generator Widget — Added a 16-character random token generator directly below the "Webhook auth token" field on the Settings page. Includes a "Generate Token" button and a clipboard copy icon with visual feedback.
Files Changed
- Modified:
inc/controllers/Settings.php
---
[3.6.0.1] — 2026-04-10
Patch
Changes
- Version bump.
---
[3.6.0.0] — 2026-04-10
Legal Agreements for Auction Approval
Features
- Terms & Conditions — A mandatory, scrollable Terms & Conditions document is now displayed during the auction approval process. Bidders must scroll to the bottom and check an agreement box before their approval request is submitted. Always enabled.
- Refund & Return Policy — An optional, scrollable Refund & Return Policy can be enabled in Settings. When enabled, bidders must read and accept it during auction approval.
- Chargeback Waiver — An optional, scrollable Chargeback Waiver can be enabled in Settings. When enabled, bidders must read and accept it during auction approval.
- Admin Management — New "Legal Agreements" page under the Bidspirit admin menu with tabbed TinyMCE editors for each agreement type. Includes automatic version numbering (incremented on content change) and full version history.
- Consent Logging — Every agreement acceptance is logged to a dedicated database table (
af_user_agreement_log) with the agreement type, version, user email, IP address, user agent, auction ID, and timestamp. - User Tracking Integration — Agreement events (
terms_agreement,refund_agreement,chargeback_waiver) are also recorded in the existing IP tracking system alongside registration, login, and bid events. - Placeholder Content — Default sample content is seeded on plugin activation for all three agreement types.
Settings Added
- Enable Refund & Return Policy — Toggle to require bidders to accept the refund policy during auction approval.
- Enable Chargeback Waiver — Toggle to require bidders to accept the chargeback waiver during auction approval.
Database
- New table:
af_legal_agreements— Current active agreement content per type - New table:
af_legal_agreement_versions— Version history archive - New table:
af_user_agreement_log— User consent records
Files Changed
- Modified:
auctionforge.php,inc/controllers/Settings.php,inc/controllers/BidspiritViews.php,inc/ip-logger.php,templates/js-chunks/approval-info.php,assets/js/app.js - Created:
inc/legal/class-legal-agreements.php,admin/view/legal-agreements.php
---
[3.5.0.6] — 2026-04-08
Bid Event Tracking
Features
- Bid Tracking — All successful bids (regular, catalog, pre-sale buyout, post-sale purchase) now fire
afLogIP("bid", bidspiritUser)to capture the bidder's full identity in the user tracking table. - Whitelist Update — Added
bidto the allowedevent_typevalues in both the local plugin and the central WPDeploy API.
---
[3.5.0.5] — 2026-04-08
Self-Healing Database Schema
Features
- Auto-Migration — The plugin now auto-detects and adds any missing tracking table columns on version upgrade, ensuring sites with older schemas seamlessly migrate without manual SQL.
---
[3.5.0.4] — 2026-04-08
API Key Auto-Healing
Features
- Seamless Self-Registration — The WordPress plugin now autonomously regenerates and saves a fresh API Key whenever WPDeploy rejects a payload with an
api_key_collisionerror. This guarantees zero-downtime security handovers when developers clone instances to proxy/staging servers.
---
[3.5.0.3] — 2026-04-08
API Key Collision Defense
Features
- 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_collisionerrors, directly instructing developers to update cloned keys.
---
[3.5.0.2] — 2026-04-08
Modal Trigger Hotfix
Fixes
- Restructured internal UI rendering priority to gracefully deploy the inline Modal triggers inside custom IP log view without colliding with cached
z-indexstacks.
---
[3.5.0.1] — 2026-04-08
Hotfix
Fixes
- Timed Auction Badge Visibility — Fixed a strict type-matching bug in the main
auction_list.phpcore file that incorrectly hid the "Timed Auction" badge overlay from valid timed/online auctions on the main upcoming/archive views. The badge now displays properly across all manual and Bidspirit-synced objects when toggled on.
Files Changed
- Modified:
templates/main/auction_list.php
---
[3.2.9.1] — 2026-03-30
Timed Auction Display Enhancements
Features
- Timed Auction Countdown Text Toggle — Added a WP-Admin setting "Change text to 'Auction will close in'" that conditionally changes the countdown label for timed/online auctions on single lot pages.
- Shortcode Text Toggle Support — Extended the new countdown text logic to the
bp_upcoming_wideshortcodes so "Live bidding starts in:" successfully transitions to "Auction will close in:" for timed auctions.
Files Changed
- Modified:
inc/controllers/Settings.php,templates/single-lot.php,templates/shortcodes/upcoming-auction-wide.php,templates/shortcodes/upcoming-auction-wide-manual.php
---
[3.2.9.0] — 2026-03-29
Billing & Invoices Polish
Fixes
- Profile Invoice ID Tracking — Prevented internal auction codes (e.g.
002orai4) from breaking into the clean hyphenated titles inside theprofile-templates.phpview. - Dynamic Payment Statuses — Replaced Bidspirit's default/cached
NOT PAIDHTML payloads by wiring thedompdfgenerator to directly respect the current$b.statusstring from the API (resolving instances where a paid invoice still printed "NOT PAID" atop the document). - Payment Instructions Conditional — Automatically hide the "Payment Instructions" block from the PDF footer when an invoice is fully paid.
- Improved Nomenclature — Changed "Invoice No:" to "Bidder No:" on document output to prevent confusion with static invoice ledger IDs.
---
[3.2.6.0] — 2026-03-28
Multi-Day Auction Lot Filtering Fix
Fixes
- Day 2+ showing lots from Day 1 in multi-day auctions — The
itemIndexcolumn inbp_meta_dataisvarchar(55), but the day-range filter inBidspiritQuery::bp_query_where()was comparing it as a string. With string comparison, lot numbers like'11','101'–'145'incorrectly fell between'1001'and'1450', causing Day 1 lots to leak into Day 2 results. Fixed by usingCAST(bpMeta.itemIndex AS UNSIGNED)for numeric comparison andintval()on the PHP-side boundary values. Letter lots (e.g.14A,1025A) are handled correctly —CASTstrips the suffix, keeping them grouped with their base lot number.
Files Changed
- Modified:
inc/controllers/BidspiritQuery.php
---
[3.2.5.9] — 2026-03-27
Catalog Page Fix
Fixes
- Duplicate preview hours on catalog pages — The
displayHoursfield was rendered twice: once via thebp_after_description_auctionhook inBidspiritViews.phpand once inline in the auction template. Removed the hook-based rendering to eliminate the duplication.
Files Changed
- Modified:
inc/controllers/BidspiritViews.php,templates/main/auction.php
---
[3.2.5] — 2026-03-19
Sync Reliability & Stuck Lot Prevention
Fixes
- CATALOG_PUBLISHED webhook now triggers catalog sync — Previously only sent push notifications without syncing lots. When the earlier AUCTION_CATALOG_UPDATED fired before the catalog was ready on BidSpirit, lots were never imported. CATALOG_PUBLISHED now calls
auctionCatalogUpdated()to trigger a full catalog sync when the catalog is actually available. - 0-lot API results now fail instead of silently succeeding — When BidSpirit API returns 0 lots (catalog not yet ready), the sync job now fails with an explicit error message, allowing the next webhook to create a fresh retry job.
- Expanded CDN allowlist in pre_http_request filter — The HTTP filter during bulk post insertion now allows all
*.bidspirit.comsubdomains and BidSpirit image CDNs (fastly.net,cloudfront.net). Previously onlybidspirit.comandwww.bidspirit.comwere allowed, blocking image downloads during sync and causing worker hangs. - InsertLotsBS timeout guard — Stage 5 (InsertLotsBS processing loop) now has a 180-second timeout and logs progress every 2 batches. Prevents indefinite hangs that previously required manual force-kill.
- fixResult() no longer marks lots as done when postId=0 — When
lotProcessing()fails to create a WP post, the staging row now keepssyncFinished=0so the lot is retried on the next sync pass, instead of being permanently marked as complete with no actual post. - lotProcessing() logs error on missing auction term — Previously returned 0 silently when
Auction::findAuctionById()failed. Now logs an explicit error that feeds intofixResult()to keep the lot retryable. - Hourly orphan detection in safety cron — New step in
syncSafety.phpdetects lot posts that exist inbp_meta_databut are missing their auction taxonomy assignment (caused by workers killed mid-batch) and auto-repairs them withwp_set_object_terms().
Files Changed
- Modified:
inc/controllers/AuctionsAPI.php,inc/sync/CatalogSyncWorker.php,inc/abs/InsertLotsAbstract.php,inc/import/InsertLotsBS.php,crontasks/syncSafety.php
---
[3.2.4] — 2026-03-18
Sync Worker Hang Fix
Fixes
- Sync workers hanging at InsertLotsBS stage — Third-party plugins (Smush Pro, SmartCrawl SEO, WPMU DEV Updates) hook into
wp_insert_post()and make blocking outbound HTTPS calls for every lot processed. With 489+ lots per auction, this caused workers to hang indefinitely on socket reads to WPMU DEV servers (32.193.94.25,32.193.93.106). AddedWP_IMPORTINGconstant at the REST worker entry point and apre_http_requestfilter inCatalogSyncWorkerthat blocks all non-essential external HTTP during the batch post-insertion phase. Loopback (127.0.0.1,localhost) and BidSpirit API calls remain allowed. - Stuck staging rows after force-kill — When workers were force-killed mid-sync, staging rows in
import_historywere left withsyncstart=1and never unblocked. Subsequent sync runs could not see these rows (filtered out byLot::getRawLots()), causing the InsertLotsBS loop to exit immediately with 0 posts processed. Combined with job deduplication (SyncQueue::enqueue()skips if aprocessingjob exists), this created a deadlock where no new sync could proceed.
Files Changed
- Modified:
auctionforge.php,inc/sync/CatalogSyncWorker.php
---
[3.2.2] — 2026-03-17
Full Sync Auction Discovery Fix
Fixes
- Full Sync finds no auctions on fresh sites — The v3
full_syncaction only queried the WordPress database for existing auction terms, but on a freshly deployed site the database has zero auctions. AddedAuctionList::init()discovery step before querying the DB, so Full Sync now fetches all auctions from the BidSpirit API and creates taxonomy terms first, then enqueues catalog sync jobs for each.
Files Changed
- Modified:
auctionforge.php
---
[3.2.0] — 2026-03-14
Webhook Pipeline Fixes, Archive Sync & Admin UI Overhaul
New Features
- Archive Sync — New "Archive Sync" button on Sync Status admin page. Enqueues catalog sync jobs for all ARCHIVED/ENDED auctions. Past auctions now appear in the auction dropdown with an optgroup separator and state label.
- Sync Tasks v3 — Replaced old v2 task cards (importData, importBidSpirit, lotBidSpiritOld) with v3 queue-based tasks. "Sync Active Auctions" and "Sync Archived Auctions" now enqueue jobs via the queue system. Maintenance tasks (Clean Draft/Trash Lots, Clean Orphaned Meta) remain as direct-execution tasks.
- How It Works guide rewritten — Complete rewrite of the admin guide for v3 architecture. Documents webhook-first flow, all 5 job types, queue system mechanics, cron setup (external + WP-Cron), configuration constants, and troubleshooting.
Fixes
- Dual-write removed — Removed legacy handlers from
auctionCatalogUpdated(),auctionDayEnded(), anditemsUpdated()webhook methods. The old handlers were racing with the v3 worker, creating orphaned staging rows inimport_historythat were never processed. All three methods now exclusively use the v3 enqueue → spawn path. - ITEMS_UPDATED webhook — Fixed
itemsUpdated()failing to enqueue jobs. TheITEMS_UPDATEDpayload hasauctionIdnested initemsByLanguage.{lang}[0].item.auctionId, not at the top level. Added extraction logic to resolve it. - ItemUpdateWorker incomplete —
ItemUpdateWorker::process()was only callingLot::bulkSave()(staging table) without runningInsertLotsBSto process staged data into WP posts andbp_meta_data. Added the InsertLotsBS processing step with autocommit restore. Item updates now flow: stage → InsertLotsBS → WP post + meta → cache clear. - Worker spawn reliability — Changed
SyncQueue::spawnWorker()from non-blocking HTTPS to blocking HTTP loopback (http://127.0.0.1with explicitHostheader, 2s timeout). Fixes nginx 403/404 errors when HTTPS loopback hits the default vhost instead of the site's vhost. - API token constant — Plugin expects
AUCTIONFORGE_API_TOKENinwp-config.php(renamed fromUCO_API_TOKENduring the plugin rename). Documented in readme.
Database
- DB version: 22 → 23
Files Changed
- Modified:
inc/controllers/AuctionsAPI.php,inc/sync/ItemUpdateWorker.php,inc/sync/SyncQueue.php,auctionforge.php,admin/view/sync-status.php,readme.txt
---
[3.0.0] — 2025-03-14
New Feature: Webhook-First Sync Architecture (Sync v3)
Overview: Complete redesign of the BidSpirit data synchronisation pipeline. Replaces the old two-phase polling system (importBidSpirit every hour + importData every minute) with a webhook-driven job queue that processes data in near real-time.
Architecture
- 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: webhook → queue → background worker → WordPress posts. - Dual-write mode — During transition, webhooks enqueue jobs AND still run the legacy handlers. Once verified, legacy handlers can be removed cleanly.
- Job deduplication — Prevents duplicate work by checking for existing pending/processing jobs with the same auction_id + job_type.
New Components
- Job Queue System (
inc/sync/SyncQueue.php) — Priority-based FIFO queue with atomic job claiming, status tracking (pending/processing/completed/failed/skipped), worker PID tracking, and automatic stuck job recovery. - Sync Logger (
inc/sync/SyncLogger.php) — Real-time log table for admin console polling with level filtering (info/success/warning/error) and incremental cursor-based retrieval. - Catalog Sync Worker (
inc/sync/CatalogSyncWorker.php) — Processes catalog_sync, full_sync, and day_ended jobs by reusing existingLotList::singleRun()logic. - Item Update Worker (
inc/sync/ItemUpdateWorker.php) — Processes individual item_update jobs with the same logic as the webhookitemsUpdatedhandler. - Background Worker (
crontasks/syncWorker.php) — Async CLI process spawned by webhooks viaexec()or by the safety cron. Claims and processes queued jobs with a configurable timeout (default 240s). - Safety Net (
crontasks/syncSafety.php) — Hourly cron that resets stuck jobs (>10min), spawns workers for pending jobs, runs a 24-hour health check (auto-enqueues full sync if no webhooks received), and purges old data.
Admin UI
- Queue Status Dashboard — New card on Sync Status page showing pending/processing/completed/failed/skipped counts, recent jobs table with real-time refresh, worker status badge, and action buttons:
- Full Sync — Enqueues catalog sync for all active auctions
- Sync Selected — Enqueue a single auction from dropdown
- Spawn Worker — Manually trigger a background worker process
- Live Console — Dark-themed terminal console on the Sync Status page. Polls
af_sync_logevery 1.5s showing timestamped, color-coded log entries from webhooks, workers, queue operations, and the safety cron. Supports pause, clear, and auto-scroll.
Cron Changes
- Removed
importData(ran every minute — ~1,440 PHP executions/day) - Removed
importBidSpirit(ran hourly — ~24 PHP executions/day) - Added
syncSafety(runs hourly at :10 — 24 PHP executions/day) - Net effect: ~62 PHP executions/hour → 1 PHP execution/hour
- WP-Cron safety hook (
auctionforge_sync_safety) — Always-active hourly event, independent of external cron - setup.sh v3 — Updated task definitions, new
migratecommand for interactive v2→v3 transition
Database
- New table:
af_sync_queue— Job queue with status, priority, source, attempts, worker PID, timing columns - New table:
af_sync_log— Real-time log entries with context, level, auction_id, job_id - DB version: 20 → 22
Constants Added
| Constant | Default | Description |
|---|---|---|
|
AUCTIONFORGE_SYNC_WORKER_TIMEOUT| 240 | Worker process timeout in seconds ||
AUCTIONFORGE_SYNC_STALE_JOB| 600 | Seconds before a processing job is considered stuck ||
AUCTIONFORGE_SYNC_HEALTH_CHECK| 86400 | Seconds without webhook before triggering full sync ||
AUCTIONFORGE_SYNC_LOG_RETENTION| 7 | Days to keep log entries ||
AUCTIONFORGE_SYNC_QUEUE_RETENTION| 30 | Days to keep completed queue jobs ||
AUCTIONFORGE_CURL_TIMEOUT| 30 | BidSpirit API cURL timeout in seconds ||
AUCTIONFORGE_PHP_BINARY| /www/server/php/83/bin/php | PHP CLI binary path for spawning workers |AJAX Handlers Added
auctionforge_sync_log_poll— Incremental log polling for live consoleauctionforge_sync_queue_status— Queue counts + recent jobs for dashboardauctionforge_sync_enqueue— Admin-triggered sync actions (full_sync, sync_auction, spawn_worker)
Fixes
- cURL timeout — BidSpiritRequest now enforces a 30-second timeout (was unlimited/0), preventing hung connections from blocking the sync pipeline.
Files Changed
- Modified:
auctionforge.php,inc/coreIncludes.php,inc/controllers/AuctionsAPI.php,inc/BidSpiritRequest.php,admin/view/sync-status.php,crontasks/setup.sh - Created:
inc/sync/SyncQueue.php,inc/sync/SyncLogger.php,inc/sync/CatalogSyncWorker.php,inc/sync/ItemUpdateWorker.php,crontasks/syncWorker.php,crontasks/syncSafety.php
---
[2.7.3.0]
Fixes
- Various stability improvements and bug fixes.
[2.7.1.2]
Fixes
- Added missing
vatAndCommission()function inloadBid()— the sales tax display on single lot pages was never being rendered because the code to callloadTemplateforvat-and-commission-templatewas missing fromapp.js.
[2.7.1.1]
Fixes
- 2 decimal places now only appear in the bid modal (Your max bid, Total Price) via
showDecimalsflag. 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.
[2.7.0.9]
Fixes
- Fixed fatal error during plugin install/upgrade:
class-stats-database.phprequire failure.
[2.7.0.0]
New Features: Advanced Lot Analytics
- Conversion Tracking, Peak Viewing Times, Pre-Sale vs Live Comparison, Category Performance, Share Analytics, Search → View Funnel, Click-Through Tracking, CSV Export, Hot Lot Badge.
- New DB table:
af_lot_shares. New columns onaf_lot_analytics. DB version bumped to 20.
[2.6.0.0]
New Feature: Lot Analytics
- Comprehensive lot view and favorite tracking system with admin dashboard.
[2.5.0.0]
New Features
- Site Statistics System — Full website analytics built into the plugin admin.
- Recently Viewed Items — Profile page tab showing last 20 viewed lots per user.
- Namespace resolution — Fixed fatal error in
-
v3.6.0.7 Stable Apr 14, 2026Download v3.6.0.7📦 8.92 MB⚙️ WP 5.2+🔧 PHP 7.2+✓ Tested 6.4
[3.6.0.7] — 2026-04-14
Hotfix
Fixes
- Namespace resolution — Fixed fatal error in
wp_footercommission label hook caused by unqualifiedSettingsHelperandSettingsclass references. Now uses fully qualified namespaces.
Files Changed
- Modified:
auctionforge.php
---
- Namespace resolution — Fixed fatal error in
-
v3.6.0.5 Stable Apr 14, 2026Download v3.6.0.5📦 8.92 MB⚙️ WP 5.2+🔧 PHP 7.2+✓ Tested 6.4
[3.6.0.5] — 2026-04-14
Commission Label Override
Features
- Commission Label Setting — New dropdown in Settings → Appearance allowing admins to choose between "Buyer's Premium" (default) and "Auction House Commission" as the label displayed on lot pages. This overrides the Bidspirit JS client's default label using a MutationObserver that catches asynchronously injected text.
Files Changed
- Modified:
inc/controllers/Settings.php,templates/single-lot.php
---
-
v3.6.0.4 Stable Apr 12, 2026Download v3.6.0.4📦 8.92 MB⚙️ WP 5.2+🔧 PHP 7.2+✓ Tested 6.4
[3.6.0.4] — 2026-04-12
Auction Approval Modal Redesign
Changes
- Removed BidSpirit Terms of Use — The generic BidSpirit "Terms of Use" section that appeared at the top of the non-credit-card approval modal has been removed. The modal now shows only the auction house's own legal agreements managed within the plugin.
- Renamed Modal Title — Changed "Terms of conditions" to "Terms & Conditions".
- Larger Scroll Area — The Terms & Conditions scroll box is now 350px tall (up from 200px) for easier reading.
- Proportional Section Heights — Refund & Return Policy and Chargeback Waiver sections use a shorter 260px scroll box to visually distinguish them from the primary Terms & Conditions.
Files Changed
- Modified:
templates/js-chunks/approval-info.php,assets/js/app.js
---
-
v3.6.0.3 Stable Apr 11, 2026Download v3.6.0.3📦 8.92 MB⚙️ WP 5.2+🔧 PHP 7.2+✓ Tested 6.4
AuctionForge Changelog
All notable changes to the AuctionForge plugin are documented in this file.
---
[3.6.0.2] — 2026-04-10
Webhook Token Generator
Features
- Token Generator Widget — Added a 16-character random token generator directly below the "Webhook auth token" field on the Settings page. Includes a "Generate Token" button and a clipboard copy icon with visual feedback.
Files Changed
- Modified:
inc/controllers/Settings.php
---
[3.6.0.1] — 2026-04-10
Patch
Changes
- Version bump.
---
[3.6.0.0] — 2026-04-10
Legal Agreements for Auction Approval
Features
- Terms & Conditions — A mandatory, scrollable Terms & Conditions document is now displayed during the auction approval process. Bidders must scroll to the bottom and check an agreement box before their approval request is submitted. Always enabled.
- Refund & Return Policy — An optional, scrollable Refund & Return Policy can be enabled in Settings. When enabled, bidders must read and accept it during auction approval.
- Chargeback Waiver — An optional, scrollable Chargeback Waiver can be enabled in Settings. When enabled, bidders must read and accept it during auction approval.
- Admin Management — New "Legal Agreements" page under the Bidspirit admin menu with tabbed TinyMCE editors for each agreement type. Includes automatic version numbering (incremented on content change) and full version history.
- Consent Logging — Every agreement acceptance is logged to a dedicated database table (
af_user_agreement_log) with the agreement type, version, user email, IP address, user agent, auction ID, and timestamp. - User Tracking Integration — Agreement events (
terms_agreement,refund_agreement,chargeback_waiver) are also recorded in the existing IP tracking system alongside registration, login, and bid events. - Placeholder Content — Default sample content is seeded on plugin activation for all three agreement types.
Settings Added
- Enable Refund & Return Policy — Toggle to require bidders to accept the refund policy during auction approval.
- Enable Chargeback Waiver — Toggle to require bidders to accept the chargeback waiver during auction approval.
Database
- New table:
af_legal_agreements— Current active agreement content per type - New table:
af_legal_agreement_versions— Version history archive - New table:
af_user_agreement_log— User consent records
Files Changed
- Modified:
auctionforge.php,inc/controllers/Settings.php,inc/controllers/BidspiritViews.php,inc/ip-logger.php,templates/js-chunks/approval-info.php,assets/js/app.js - Created:
inc/legal/class-legal-agreements.php,admin/view/legal-agreements.php
---
[3.5.0.6] — 2026-04-08
Bid Event Tracking
Features
- Bid Tracking — All successful bids (regular, catalog, pre-sale buyout, post-sale purchase) now fire
afLogIP("bid", bidspiritUser)to capture the bidder's full identity in the user tracking table. - Whitelist Update — Added
bidto the allowedevent_typevalues in both the local plugin and the central WPDeploy API.
---
[3.5.0.5] — 2026-04-08
Self-Healing Database Schema
Features
- Auto-Migration — The plugin now auto-detects and adds any missing tracking table columns on version upgrade, ensuring sites with older schemas seamlessly migrate without manual SQL.
---
[3.5.0.4] — 2026-04-08
API Key Auto-Healing
Features
- Seamless Self-Registration — The WordPress plugin now autonomously regenerates and saves a fresh API Key whenever WPDeploy rejects a payload with an
api_key_collisionerror. This guarantees zero-downtime security handovers when developers clone instances to proxy/staging servers.
---
[3.5.0.3] — 2026-04-08
API Key Collision Defense
Features
- 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_collisionerrors, directly instructing developers to update cloned keys.
---
[3.5.0.2] — 2026-04-08
Modal Trigger Hotfix
Fixes
- Restructured internal UI rendering priority to gracefully deploy the inline Modal triggers inside custom IP log view without colliding with cached
z-indexstacks.
---
[3.5.0.1] — 2026-04-08
Hotfix
Fixes
- Timed Auction Badge Visibility — Fixed a strict type-matching bug in the main
auction_list.phpcore file that incorrectly hid the "Timed Auction" badge overlay from valid timed/online auctions on the main upcoming/archive views. The badge now displays properly across all manual and Bidspirit-synced objects when toggled on.
Files Changed
- Modified:
templates/main/auction_list.php
---
[3.2.9.1] — 2026-03-30
Timed Auction Display Enhancements
Features
- Timed Auction Countdown Text Toggle — Added a WP-Admin setting "Change text to 'Auction will close in'" that conditionally changes the countdown label for timed/online auctions on single lot pages.
- Shortcode Text Toggle Support — Extended the new countdown text logic to the
bp_upcoming_wideshortcodes so "Live bidding starts in:" successfully transitions to "Auction will close in:" for timed auctions.
Files Changed
- Modified:
inc/controllers/Settings.php,templates/single-lot.php,templates/shortcodes/upcoming-auction-wide.php,templates/shortcodes/upcoming-auction-wide-manual.php
---
[3.2.9.0] — 2026-03-29
Billing & Invoices Polish
Fixes
- Profile Invoice ID Tracking — Prevented internal auction codes (e.g.
002orai4) from breaking into the clean hyphenated titles inside theprofile-templates.phpview. - Dynamic Payment Statuses — Replaced Bidspirit's default/cached
NOT PAIDHTML payloads by wiring thedompdfgenerator to directly respect the current$b.statusstring from the API (resolving instances where a paid invoice still printed "NOT PAID" atop the document). - Payment Instructions Conditional — Automatically hide the "Payment Instructions" block from the PDF footer when an invoice is fully paid.
- Improved Nomenclature — Changed "Invoice No:" to "Bidder No:" on document output to prevent confusion with static invoice ledger IDs.
---
[3.2.6.0] — 2026-03-28
Multi-Day Auction Lot Filtering Fix
Fixes
- Day 2+ showing lots from Day 1 in multi-day auctions — The
itemIndexcolumn inbp_meta_dataisvarchar(55), but the day-range filter inBidspiritQuery::bp_query_where()was comparing it as a string. With string comparison, lot numbers like'11','101'–'145'incorrectly fell between'1001'and'1450', causing Day 1 lots to leak into Day 2 results. Fixed by usingCAST(bpMeta.itemIndex AS UNSIGNED)for numeric comparison andintval()on the PHP-side boundary values. Letter lots (e.g.14A,1025A) are handled correctly —CASTstrips the suffix, keeping them grouped with their base lot number.
Files Changed
- Modified:
inc/controllers/BidspiritQuery.php
---
[3.2.5.9] — 2026-03-27
Catalog Page Fix
Fixes
- Duplicate preview hours on catalog pages — The
displayHoursfield was rendered twice: once via thebp_after_description_auctionhook inBidspiritViews.phpand once inline in the auction template. Removed the hook-based rendering to eliminate the duplication.
Files Changed
- Modified:
inc/controllers/BidspiritViews.php,templates/main/auction.php
---
[3.2.5] — 2026-03-19
Sync Reliability & Stuck Lot Prevention
Fixes
- CATALOG_PUBLISHED webhook now triggers catalog sync — Previously only sent push notifications without syncing lots. When the earlier AUCTION_CATALOG_UPDATED fired before the catalog was ready on BidSpirit, lots were never imported. CATALOG_PUBLISHED now calls
auctionCatalogUpdated()to trigger a full catalog sync when the catalog is actually available. - 0-lot API results now fail instead of silently succeeding — When BidSpirit API returns 0 lots (catalog not yet ready), the sync job now fails with an explicit error message, allowing the next webhook to create a fresh retry job.
- Expanded CDN allowlist in pre_http_request filter — The HTTP filter during bulk post insertion now allows all
*.bidspirit.comsubdomains and BidSpirit image CDNs (fastly.net,cloudfront.net). Previously onlybidspirit.comandwww.bidspirit.comwere allowed, blocking image downloads during sync and causing worker hangs. - InsertLotsBS timeout guard — Stage 5 (InsertLotsBS processing loop) now has a 180-second timeout and logs progress every 2 batches. Prevents indefinite hangs that previously required manual force-kill.
- fixResult() no longer marks lots as done when postId=0 — When
lotProcessing()fails to create a WP post, the staging row now keepssyncFinished=0so the lot is retried on the next sync pass, instead of being permanently marked as complete with no actual post. - lotProcessing() logs error on missing auction term — Previously returned 0 silently when
Auction::findAuctionById()failed. Now logs an explicit error that feeds intofixResult()to keep the lot retryable. - Hourly orphan detection in safety cron — New step in
syncSafety.phpdetects lot posts that exist inbp_meta_databut are missing their auction taxonomy assignment (caused by workers killed mid-batch) and auto-repairs them withwp_set_object_terms().
Files Changed
- Modified:
inc/controllers/AuctionsAPI.php,inc/sync/CatalogSyncWorker.php,inc/abs/InsertLotsAbstract.php,inc/import/InsertLotsBS.php,crontasks/syncSafety.php
---
[3.2.4] — 2026-03-18
Sync Worker Hang Fix
Fixes
- Sync workers hanging at InsertLotsBS stage — Third-party plugins (Smush Pro, SmartCrawl SEO, WPMU DEV Updates) hook into
wp_insert_post()and make blocking outbound HTTPS calls for every lot processed. With 489+ lots per auction, this caused workers to hang indefinitely on socket reads to WPMU DEV servers (32.193.94.25,32.193.93.106). AddedWP_IMPORTINGconstant at the REST worker entry point and apre_http_requestfilter inCatalogSyncWorkerthat blocks all non-essential external HTTP during the batch post-insertion phase. Loopback (127.0.0.1,localhost) and BidSpirit API calls remain allowed. - Stuck staging rows after force-kill — When workers were force-killed mid-sync, staging rows in
import_historywere left withsyncstart=1and never unblocked. Subsequent sync runs could not see these rows (filtered out byLot::getRawLots()), causing the InsertLotsBS loop to exit immediately with 0 posts processed. Combined with job deduplication (SyncQueue::enqueue()skips if aprocessingjob exists), this created a deadlock where no new sync could proceed.
Files Changed
- Modified:
auctionforge.php,inc/sync/CatalogSyncWorker.php
---
[3.2.2] — 2026-03-17
Full Sync Auction Discovery Fix
Fixes
- Full Sync finds no auctions on fresh sites — The v3
full_syncaction only queried the WordPress database for existing auction terms, but on a freshly deployed site the database has zero auctions. AddedAuctionList::init()discovery step before querying the DB, so Full Sync now fetches all auctions from the BidSpirit API and creates taxonomy terms first, then enqueues catalog sync jobs for each.
Files Changed
- Modified:
auctionforge.php
---
[3.2.0] — 2026-03-14
Webhook Pipeline Fixes, Archive Sync & Admin UI Overhaul
New Features
- Archive Sync — New "Archive Sync" button on Sync Status admin page. Enqueues catalog sync jobs for all ARCHIVED/ENDED auctions. Past auctions now appear in the auction dropdown with an optgroup separator and state label.
- Sync Tasks v3 — Replaced old v2 task cards (importData, importBidSpirit, lotBidSpiritOld) with v3 queue-based tasks. "Sync Active Auctions" and "Sync Archived Auctions" now enqueue jobs via the queue system. Maintenance tasks (Clean Draft/Trash Lots, Clean Orphaned Meta) remain as direct-execution tasks.
- How It Works guide rewritten — Complete rewrite of the admin guide for v3 architecture. Documents webhook-first flow, all 5 job types, queue system mechanics, cron setup (external + WP-Cron), configuration constants, and troubleshooting.
Fixes
- Dual-write removed — Removed legacy handlers from
auctionCatalogUpdated(),auctionDayEnded(), anditemsUpdated()webhook methods. The old handlers were racing with the v3 worker, creating orphaned staging rows inimport_historythat were never processed. All three methods now exclusively use the v3 enqueue → spawn path. - ITEMS_UPDATED webhook — Fixed
itemsUpdated()failing to enqueue jobs. TheITEMS_UPDATEDpayload hasauctionIdnested initemsByLanguage.{lang}[0].item.auctionId, not at the top level. Added extraction logic to resolve it. - ItemUpdateWorker incomplete —
ItemUpdateWorker::process()was only callingLot::bulkSave()(staging table) without runningInsertLotsBSto process staged data into WP posts andbp_meta_data. Added the InsertLotsBS processing step with autocommit restore. Item updates now flow: stage → InsertLotsBS → WP post + meta → cache clear. - Worker spawn reliability — Changed
SyncQueue::spawnWorker()from non-blocking HTTPS to blocking HTTP loopback (http://127.0.0.1with explicitHostheader, 2s timeout). Fixes nginx 403/404 errors when HTTPS loopback hits the default vhost instead of the site's vhost. - API token constant — Plugin expects
AUCTIONFORGE_API_TOKENinwp-config.php(renamed fromUCO_API_TOKENduring the plugin rename). Documented in readme.
Database
- DB version: 22 → 23
Files Changed
- Modified:
inc/controllers/AuctionsAPI.php,inc/sync/ItemUpdateWorker.php,inc/sync/SyncQueue.php,auctionforge.php,admin/view/sync-status.php,readme.txt
---
[3.0.0] — 2025-03-14
New Feature: Webhook-First Sync Architecture (Sync v3)
Overview: Complete redesign of the BidSpirit data synchronisation pipeline. Replaces the old two-phase polling system (importBidSpirit every hour + importData every minute) with a webhook-driven job queue that processes data in near real-time.
Architecture
- 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: webhook → queue → background worker → WordPress posts. - Dual-write mode — During transition, webhooks enqueue jobs AND still run the legacy handlers. Once verified, legacy handlers can be removed cleanly.
- Job deduplication — Prevents duplicate work by checking for existing pending/processing jobs with the same auction_id + job_type.
New Components
- Job Queue System (
inc/sync/SyncQueue.php) — Priority-based FIFO queue with atomic job claiming, status tracking (pending/processing/completed/failed/skipped), worker PID tracking, and automatic stuck job recovery. - Sync Logger (
inc/sync/SyncLogger.php) — Real-time log table for admin console polling with level filtering (info/success/warning/error) and incremental cursor-based retrieval. - Catalog Sync Worker (
inc/sync/CatalogSyncWorker.php) — Processes catalog_sync, full_sync, and day_ended jobs by reusing existingLotList::singleRun()logic. - Item Update Worker (
inc/sync/ItemUpdateWorker.php) — Processes individual item_update jobs with the same logic as the webhookitemsUpdatedhandler. - Background Worker (
crontasks/syncWorker.php) — Async CLI process spawned by webhooks viaexec()or by the safety cron. Claims and processes queued jobs with a configurable timeout (default 240s). - Safety Net (
crontasks/syncSafety.php) — Hourly cron that resets stuck jobs (>10min), spawns workers for pending jobs, runs a 24-hour health check (auto-enqueues full sync if no webhooks received), and purges old data.
Admin UI
- Queue Status Dashboard — New card on Sync Status page showing pending/processing/completed/failed/skipped counts, recent jobs table with real-time refresh, worker status badge, and action buttons:
- Full Sync — Enqueues catalog sync for all active auctions
- Sync Selected — Enqueue a single auction from dropdown
- Spawn Worker — Manually trigger a background worker process
- Live Console — Dark-themed terminal console on the Sync Status page. Polls
af_sync_logevery 1.5s showing timestamped, color-coded log entries from webhooks, workers, queue operations, and the safety cron. Supports pause, clear, and auto-scroll.
Cron Changes
- Removed
importData(ran every minute — ~1,440 PHP executions/day) - Removed
importBidSpirit(ran hourly — ~24 PHP executions/day) - Added
syncSafety(runs hourly at :10 — 24 PHP executions/day) - Net effect: ~62 PHP executions/hour → 1 PHP execution/hour
- WP-Cron safety hook (
auctionforge_sync_safety) — Always-active hourly event, independent of external cron - setup.sh v3 — Updated task definitions, new
migratecommand for interactive v2→v3 transition
Database
- New table:
af_sync_queue— Job queue with status, priority, source, attempts, worker PID, timing columns - New table:
af_sync_log— Real-time log entries with context, level, auction_id, job_id - DB version: 20 → 22
Constants Added
| Constant | Default | Description |
|---|---|---|
|
AUCTIONFORGE_SYNC_WORKER_TIMEOUT| 240 | Worker process timeout in seconds ||
AUCTIONFORGE_SYNC_STALE_JOB| 600 | Seconds before a processing job is considered stuck ||
AUCTIONFORGE_SYNC_HEALTH_CHECK| 86400 | Seconds without webhook before triggering full sync ||
AUCTIONFORGE_SYNC_LOG_RETENTION| 7 | Days to keep log entries ||
AUCTIONFORGE_SYNC_QUEUE_RETENTION| 30 | Days to keep completed queue jobs ||
AUCTIONFORGE_CURL_TIMEOUT| 30 | BidSpirit API cURL timeout in seconds ||
AUCTIONFORGE_PHP_BINARY| /www/server/php/83/bin/php | PHP CLI binary path for spawning workers |AJAX Handlers Added
auctionforge_sync_log_poll— Incremental log polling for live consoleauctionforge_sync_queue_status— Queue counts + recent jobs for dashboardauctionforge_sync_enqueue— Admin-triggered sync actions (full_sync, sync_auction, spawn_worker)
Fixes
- cURL timeout — BidSpiritRequest now enforces a 30-second timeout (was unlimited/0), preventing hung connections from blocking the sync pipeline.
Files Changed
- Modified:
auctionforge.php,inc/coreIncludes.php,inc/controllers/AuctionsAPI.php,inc/BidSpiritRequest.php,admin/view/sync-status.php,crontasks/setup.sh - Created:
inc/sync/SyncQueue.php,inc/sync/SyncLogger.php,inc/sync/CatalogSyncWorker.php,inc/sync/ItemUpdateWorker.php,crontasks/syncWorker.php,crontasks/syncSafety.php
---
[2.7.3.0]
Fixes
- Various stability improvements and bug fixes.
[2.7.1.2]
Fixes
- Added missing
vatAndCommission()function inloadBid()— the sales tax display on single lot pages was never being rendered because the code to callloadTemplateforvat-and-commission-templatewas missing fromapp.js.
[2.7.1.1]
Fixes
- 2 decimal places now only appear in the bid modal (Your max bid, Total Price) via
showDecimalsflag. 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.
[2.7.0.9]
Fixes
- Fixed fatal error during plugin install/upgrade:
class-stats-database.phprequire failure.
[2.7.0.0]
New Features: Advanced Lot Analytics
- Conversion Tracking, Peak Viewing Times, Pre-Sale vs Live Comparison, Category Performance, Share Analytics, Search → View Funnel, Click-Through Tracking, CSV Export, Hot Lot Badge.
- New DB table:
af_lot_shares. New columns onaf_lot_analytics. DB version bumped to 20.
[2.6.0.0]
New Feature: Lot Analytics
- Comprehensive lot view and favorite tracking system with admin dashboard.
[2.5.0.0]
New Features
- Site Statistics System — Full website analytics built into the plugin admin.
- Recently Viewed Items — Profile page tab showing last 20 viewed lots per user.
-
v3.6.0.2 Stable Apr 10, 2026Download v3.6.0.2📦 8.91 MB⚙️ WP 5.2+🔧 PHP 7.2+✓ Tested 6.4
[3.6.0.2] — 2026-04-10
Webhook Token Generator
Features
- Token Generator Widget — Added a 16-character random token generator directly below the "Webhook auth token" field on the Settings page. Includes a "Generate Token" button and a clipboard copy icon with visual feedback.
Files Changed
- Modified:
inc/controllers/Settings.php
---
-
v3.6.0.0 Stable Apr 10, 2026Download v3.6.0.0📦 8.89 MB⚙️ WP 5.2+🔧 PHP 7.2+✓ Tested 6.4
AuctionForge Changelog
All notable changes to the AuctionForge plugin are documented in this file.
---
[3.5.0.6] — 2026-04-08
Bid Event Tracking
Features
- Bid Tracking — All successful bids (regular, catalog, pre-sale buyout, post-sale purchase) now fire
afLogIP("bid", bidspiritUser)to capture the bidder's full identity in the user tracking table. - Whitelist Update — Added
bidto the allowedevent_typevalues in both the local plugin and the central WPDeploy API.
---
[3.5.0.5] — 2026-04-08
Self-Healing Database Schema
Features
- Auto-Migration — The plugin now auto-detects and adds any missing tracking table columns on version upgrade, ensuring sites with older schemas seamlessly migrate without manual SQL.
---
[3.5.0.4] — 2026-04-08
API Key Auto-Healing
Features
- Seamless Self-Registration — The WordPress plugin now autonomously regenerates and saves a fresh API Key whenever WPDeploy rejects a payload with an
api_key_collisionerror. This guarantees zero-downtime security handovers when developers clone instances to proxy/staging servers.
---
[3.5.0.3] — 2026-04-08
API Key Collision Defense
Features
- 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_collisionerrors, directly instructing developers to update cloned keys.
---
[3.5.0.2] — 2026-04-08
Modal Trigger Hotfix
Fixes
- Restructured internal UI rendering priority to gracefully deploy the inline Modal triggers inside custom IP log view without colliding with cached
z-indexstacks.
---
[3.5.0.1] — 2026-04-08
Hotfix
Fixes
- Timed Auction Badge Visibility — Fixed a strict type-matching bug in the main
auction_list.phpcore file that incorrectly hid the "Timed Auction" badge overlay from valid timed/online auctions on the main upcoming/archive views. The badge now displays properly across all manual and Bidspirit-synced objects when toggled on.
Files Changed
- Modified:
templates/main/auction_list.php
---
[3.2.9.1] — 2026-03-30
Timed Auction Display Enhancements
Features
- Timed Auction Countdown Text Toggle — Added a WP-Admin setting "Change text to 'Auction will close in'" that conditionally changes the countdown label for timed/online auctions on single lot pages.
- Shortcode Text Toggle Support — Extended the new countdown text logic to the
bp_upcoming_wideshortcodes so "Live bidding starts in:" successfully transitions to "Auction will close in:" for timed auctions.
Files Changed
- Modified:
inc/controllers/Settings.php,templates/single-lot.php,templates/shortcodes/upcoming-auction-wide.php,templates/shortcodes/upcoming-auction-wide-manual.php
---
[3.2.9.0] — 2026-03-29
Billing & Invoices Polish
Fixes
- Profile Invoice ID Tracking — Prevented internal auction codes (e.g.
002orai4) from breaking into the clean hyphenated titles inside theprofile-templates.phpview. - Dynamic Payment Statuses — Replaced Bidspirit's default/cached
NOT PAIDHTML payloads by wiring thedompdfgenerator to directly respect the current$b.statusstring from the API (resolving instances where a paid invoice still printed "NOT PAID" atop the document). - Payment Instructions Conditional — Automatically hide the "Payment Instructions" block from the PDF footer when an invoice is fully paid.
- Improved Nomenclature — Changed "Invoice No:" to "Bidder No:" on document output to prevent confusion with static invoice ledger IDs.
---
[3.2.6.0] — 2026-03-28
Multi-Day Auction Lot Filtering Fix
Fixes
- Day 2+ showing lots from Day 1 in multi-day auctions — The
itemIndexcolumn inbp_meta_dataisvarchar(55), but the day-range filter inBidspiritQuery::bp_query_where()was comparing it as a string. With string comparison, lot numbers like'11','101'–'145'incorrectly fell between'1001'and'1450', causing Day 1 lots to leak into Day 2 results. Fixed by usingCAST(bpMeta.itemIndex AS UNSIGNED)for numeric comparison andintval()on the PHP-side boundary values. Letter lots (e.g.14A,1025A) are handled correctly —CASTstrips the suffix, keeping them grouped with their base lot number.
Files Changed
- Modified:
inc/controllers/BidspiritQuery.php
---
[3.2.5.9] — 2026-03-27
Catalog Page Fix
Fixes
- Duplicate preview hours on catalog pages — The
displayHoursfield was rendered twice: once via thebp_after_description_auctionhook inBidspiritViews.phpand once inline in the auction template. Removed the hook-based rendering to eliminate the duplication.
Files Changed
- Modified:
inc/controllers/BidspiritViews.php,templates/main/auction.php
---
[3.2.5] — 2026-03-19
Sync Reliability & Stuck Lot Prevention
Fixes
- CATALOG_PUBLISHED webhook now triggers catalog sync — Previously only sent push notifications without syncing lots. When the earlier AUCTION_CATALOG_UPDATED fired before the catalog was ready on BidSpirit, lots were never imported. CATALOG_PUBLISHED now calls
auctionCatalogUpdated()to trigger a full catalog sync when the catalog is actually available. - 0-lot API results now fail instead of silently succeeding — When BidSpirit API returns 0 lots (catalog not yet ready), the sync job now fails with an explicit error message, allowing the next webhook to create a fresh retry job.
- Expanded CDN allowlist in pre_http_request filter — The HTTP filter during bulk post insertion now allows all
*.bidspirit.comsubdomains and BidSpirit image CDNs (fastly.net,cloudfront.net). Previously onlybidspirit.comandwww.bidspirit.comwere allowed, blocking image downloads during sync and causing worker hangs. - InsertLotsBS timeout guard — Stage 5 (InsertLotsBS processing loop) now has a 180-second timeout and logs progress every 2 batches. Prevents indefinite hangs that previously required manual force-kill.
- fixResult() no longer marks lots as done when postId=0 — When
lotProcessing()fails to create a WP post, the staging row now keepssyncFinished=0so the lot is retried on the next sync pass, instead of being permanently marked as complete with no actual post. - lotProcessing() logs error on missing auction term — Previously returned 0 silently when
Auction::findAuctionById()failed. Now logs an explicit error that feeds intofixResult()to keep the lot retryable. - Hourly orphan detection in safety cron — New step in
syncSafety.phpdetects lot posts that exist inbp_meta_databut are missing their auction taxonomy assignment (caused by workers killed mid-batch) and auto-repairs them withwp_set_object_terms().
Files Changed
- Modified:
inc/controllers/AuctionsAPI.php,inc/sync/CatalogSyncWorker.php,inc/abs/InsertLotsAbstract.php,inc/import/InsertLotsBS.php,crontasks/syncSafety.php
---
[3.2.4] — 2026-03-18
Sync Worker Hang Fix
Fixes
- Sync workers hanging at InsertLotsBS stage — Third-party plugins (Smush Pro, SmartCrawl SEO, WPMU DEV Updates) hook into
wp_insert_post()and make blocking outbound HTTPS calls for every lot processed. With 489+ lots per auction, this caused workers to hang indefinitely on socket reads to WPMU DEV servers (32.193.94.25,32.193.93.106). AddedWP_IMPORTINGconstant at the REST worker entry point and apre_http_requestfilter inCatalogSyncWorkerthat blocks all non-essential external HTTP during the batch post-insertion phase. Loopback (127.0.0.1,localhost) and BidSpirit API calls remain allowed. - Stuck staging rows after force-kill — When workers were force-killed mid-sync, staging rows in
import_historywere left withsyncstart=1and never unblocked. Subsequent sync runs could not see these rows (filtered out byLot::getRawLots()), causing the InsertLotsBS loop to exit immediately with 0 posts processed. Combined with job deduplication (SyncQueue::enqueue()skips if aprocessingjob exists), this created a deadlock where no new sync could proceed.
Files Changed
- Modified:
auctionforge.php,inc/sync/CatalogSyncWorker.php
---
[3.2.2] — 2026-03-17
Full Sync Auction Discovery Fix
Fixes
- Full Sync finds no auctions on fresh sites — The v3
full_syncaction only queried the WordPress database for existing auction terms, but on a freshly deployed site the database has zero auctions. AddedAuctionList::init()discovery step before querying the DB, so Full Sync now fetches all auctions from the BidSpirit API and creates taxonomy terms first, then enqueues catalog sync jobs for each.
Files Changed
- Modified:
auctionforge.php
---
[3.2.0] — 2026-03-14
Webhook Pipeline Fixes, Archive Sync & Admin UI Overhaul
New Features
- Archive Sync — New "Archive Sync" button on Sync Status admin page. Enqueues catalog sync jobs for all ARCHIVED/ENDED auctions. Past auctions now appear in the auction dropdown with an optgroup separator and state label.
- Sync Tasks v3 — Replaced old v2 task cards (importData, importBidSpirit, lotBidSpiritOld) with v3 queue-based tasks. "Sync Active Auctions" and "Sync Archived Auctions" now enqueue jobs via the queue system. Maintenance tasks (Clean Draft/Trash Lots, Clean Orphaned Meta) remain as direct-execution tasks.
- How It Works guide rewritten — Complete rewrite of the admin guide for v3 architecture. Documents webhook-first flow, all 5 job types, queue system mechanics, cron setup (external + WP-Cron), configuration constants, and troubleshooting.
Fixes
- Dual-write removed — Removed legacy handlers from
auctionCatalogUpdated(),auctionDayEnded(), anditemsUpdated()webhook methods. The old handlers were racing with the v3 worker, creating orphaned staging rows inimport_historythat were never processed. All three methods now exclusively use the v3 enqueue → spawn path. - ITEMS_UPDATED webhook — Fixed
itemsUpdated()failing to enqueue jobs. TheITEMS_UPDATEDpayload hasauctionIdnested initemsByLanguage.{lang}[0].item.auctionId, not at the top level. Added extraction logic to resolve it. - ItemUpdateWorker incomplete —
ItemUpdateWorker::process()was only callingLot::bulkSave()(staging table) without runningInsertLotsBSto process staged data into WP posts andbp_meta_data. Added the InsertLotsBS processing step with autocommit restore. Item updates now flow: stage → InsertLotsBS → WP post + meta → cache clear. - Worker spawn reliability — Changed
SyncQueue::spawnWorker()from non-blocking HTTPS to blocking HTTP loopback (http://127.0.0.1with explicitHostheader, 2s timeout). Fixes nginx 403/404 errors when HTTPS loopback hits the default vhost instead of the site's vhost. - API token constant — Plugin expects
AUCTIONFORGE_API_TOKENinwp-config.php(renamed fromUCO_API_TOKENduring the plugin rename). Documented in readme.
Database
- DB version: 22 → 23
Files Changed
- Modified:
inc/controllers/AuctionsAPI.php,inc/sync/ItemUpdateWorker.php,inc/sync/SyncQueue.php,auctionforge.php,admin/view/sync-status.php,readme.txt
---
[3.0.0] — 2025-03-14
New Feature: Webhook-First Sync Architecture (Sync v3)
Overview: Complete redesign of the BidSpirit data synchronisation pipeline. Replaces the old two-phase polling system (importBidSpirit every hour + importData every minute) with a webhook-driven job queue that processes data in near real-time.
Architecture
- 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: webhook → queue → background worker → WordPress posts. - Dual-write mode — During transition, webhooks enqueue jobs AND still run the legacy handlers. Once verified, legacy handlers can be removed cleanly.
- Job deduplication — Prevents duplicate work by checking for existing pending/processing jobs with the same auction_id + job_type.
New Components
- Job Queue System (
inc/sync/SyncQueue.php) — Priority-based FIFO queue with atomic job claiming, status tracking (pending/processing/completed/failed/skipped), worker PID tracking, and automatic stuck job recovery. - Sync Logger (
inc/sync/SyncLogger.php) — Real-time log table for admin console polling with level filtering (info/success/warning/error) and incremental cursor-based retrieval. - Catalog Sync Worker (
inc/sync/CatalogSyncWorker.php) — Processes catalog_sync, full_sync, and day_ended jobs by reusing existingLotList::singleRun()logic. - Item Update Worker (
inc/sync/ItemUpdateWorker.php) — Processes individual item_update jobs with the same logic as the webhookitemsUpdatedhandler. - Background Worker (
crontasks/syncWorker.php) — Async CLI process spawned by webhooks viaexec()or by the safety cron. Claims and processes queued jobs with a configurable timeout (default 240s). - Safety Net (
crontasks/syncSafety.php) — Hourly cron that resets stuck jobs (>10min), spawns workers for pending jobs, runs a 24-hour health check (auto-enqueues full sync if no webhooks received), and purges old data.
Admin UI
- Queue Status Dashboard — New card on Sync Status page showing pending/processing/completed/failed/skipped counts, recent jobs table with real-time refresh, worker status badge, and action buttons:
- Full Sync — Enqueues catalog sync for all active auctions
- Sync Selected — Enqueue a single auction from dropdown
- Spawn Worker — Manually trigger a background worker process
- Live Console — Dark-themed terminal console on the Sync Status page. Polls
af_sync_logevery 1.5s showing timestamped, color-coded log entries from webhooks, workers, queue operations, and the safety cron. Supports pause, clear, and auto-scroll.
Cron Changes
- Removed
importData(ran every minute — ~1,440 PHP executions/day) - Removed
importBidSpirit(ran hourly — ~24 PHP executions/day) - Added
syncSafety(runs hourly at :10 — 24 PHP executions/day) - Net effect: ~62 PHP executions/hour → 1 PHP execution/hour
- WP-Cron safety hook (
auctionforge_sync_safety) — Always-active hourly event, independent of external cron - setup.sh v3 — Updated task definitions, new
migratecommand for interactive v2→v3 transition
Database
- New table:
af_sync_queue— Job queue with status, priority, source, attempts, worker PID, timing columns - New table:
af_sync_log— Real-time log entries with context, level, auction_id, job_id - DB version: 20 → 22
Constants Added
| Constant | Default | Description |
|---|---|---|
|
AUCTIONFORGE_SYNC_WORKER_TIMEOUT| 240 | Worker process timeout in seconds ||
AUCTIONFORGE_SYNC_STALE_JOB| 600 | Seconds before a processing job is considered stuck ||
AUCTIONFORGE_SYNC_HEALTH_CHECK| 86400 | Seconds without webhook before triggering full sync ||
AUCTIONFORGE_SYNC_LOG_RETENTION| 7 | Days to keep log entries ||
AUCTIONFORGE_SYNC_QUEUE_RETENTION| 30 | Days to keep completed queue jobs ||
AUCTIONFORGE_CURL_TIMEOUT| 30 | BidSpirit API cURL timeout in seconds ||
AUCTIONFORGE_PHP_BINARY| /www/server/php/83/bin/php | PHP CLI binary path for spawning workers |AJAX Handlers Added
auctionforge_sync_log_poll— Incremental log polling for live consoleauctionforge_sync_queue_status— Queue counts + recent jobs for dashboardauctionforge_sync_enqueue— Admin-triggered sync actions (full_sync, sync_auction, spawn_worker)
Fixes
- cURL timeout — BidSpiritRequest now enforces a 30-second timeout (was unlimited/0), preventing hung connections from blocking the sync pipeline.
Files Changed
- Modified:
auctionforge.php,inc/coreIncludes.php,inc/controllers/AuctionsAPI.php,inc/BidSpiritRequest.php,admin/view/sync-status.php,crontasks/setup.sh - Created:
inc/sync/SyncQueue.php,inc/sync/SyncLogger.php,inc/sync/CatalogSyncWorker.php,inc/sync/ItemUpdateWorker.php,crontasks/syncWorker.php,crontasks/syncSafety.php
---
[2.7.3.0]
Fixes
- Various stability improvements and bug fixes.
[2.7.1.2]
Fixes
- Added missing
vatAndCommission()function inloadBid()— the sales tax display on single lot pages was never being rendered because the code to callloadTemplateforvat-and-commission-templatewas missing fromapp.js.
[2.7.1.1]
Fixes
- 2 decimal places now only appear in the bid modal (Your max bid, Total Price) via
showDecimalsflag. 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.
[2.7.0.9]
Fixes
- Fixed fatal error during plugin install/upgrade:
class-stats-database.phprequire failure.
[2.7.0.0]
New Features: Advanced Lot Analytics
- Conversion Tracking, Peak Viewing Times, Pre-Sale vs Live Comparison, Category Performance, Share Analytics, Search → View Funnel, Click-Through Tracking, CSV Export, Hot Lot Badge.
- New DB table:
af_lot_shares. New columns onaf_lot_analytics. DB version bumped to 20.
[2.6.0.0]
New Feature: Lot Analytics
- Comprehensive lot view and favorite tracking system with admin dashboard.
[2.5.0.0]
New Features
- Site Statistics System — Full website analytics built into the plugin admin.
- Recently Viewed Items — Profile page tab showing last 20 viewed lots per user.
- Bid Tracking — All successful bids (regular, catalog, pre-sale buyout, post-sale purchase) now fire
-
v3.5.0.5 Stable Apr 08, 2026Download v3.5.0.5📦 9.15 MB⚙️ WP 5.2+🔧 PHP 7.2+✓ Tested 6.6.1
Self-Healing Database Schema + Bid Event Tracking — Auto-migrates missing tracking columns on upgrade and tracks all user bids (regular, pre-sale buyout, post-sale purchase) in the user tracking system.
-
v3.5.0.4 Stable Apr 08, 2026Download v3.5.0.4📦 9.15 MB⚙️ WP 5.2+🔧 PHP 7.2+✓ Tested 6.6.1
API Key Auto-Healing — The WordPress plugin now autonomously regenerates and saves a fresh API Key whenever WPDeploy rejects a payload with an api_key_collision error. This guarantees zero-downtime security handovers when developers clone instances to proxy/staging servers.
-
v3.5.0.6 Stable Apr 08, 2026Download v3.5.0.6📦 9.15 MB⚙️ WP 5.2+🔧 PHP 7.2+✓ Tested 6.6.1
Bid Event Tracking + Self-Healing Schema — All bids now tracked with full user fingerprint identity. Auto-migrates missing DB columns on upgrade.
-
v3.5.0.3 Stable Apr 08, 2026Download v3.5.0.3📦 9.15 MB⚙️ WP 5.2+🔧 PHP 7.2+✓ Tested 6.6.1
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.
-
v3.5.0.2 Stable Apr 08, 2026Download v3.5.0.2📦 9.15 MB⚙️ WP 5.2+🔧 PHP 7.2+✓ Tested 6.4
AuctionForge Changelog
All notable changes to the AuctionForge plugin are documented in this file.
---
[3.2.9.2] — 2026-03-30
Timed Auction Archive Fix
Fixes
- Timed Auction Badge Visibility — Fixed a strict type-matching bug in the main
auction_list.phpcore file that incorrectly hid the "Timed Auction" badge overlay from valid timed/online auctions on the main upcoming/archive views. The badge now displays properly across all manual and Bidspirit-synced objects when toggled on.
Files Changed
- Modified:
templates/main/auction_list.php
---
[3.2.9.1] — 2026-03-30
Timed Auction Display Enhancements
Features
- Timed Auction Countdown Text Toggle — Added a WP-Admin setting "Change text to 'Auction will close in'" that conditionally changes the countdown label for timed/online auctions on single lot pages.
- Shortcode Text Toggle Support — Extended the new countdown text logic to the
bp_upcoming_wideshortcodes so "Live bidding starts in:" successfully transitions to "Auction will close in:" for timed auctions.
Files Changed
- Modified:
inc/controllers/Settings.php,templates/single-lot.php,templates/shortcodes/upcoming-auction-wide.php,templates/shortcodes/upcoming-auction-wide-manual.php
---
[3.2.9.0] — 2026-03-29
Billing & Invoices Polish
Fixes
- Profile Invoice ID Tracking — Prevented internal auction codes (e.g.
002orai4) from breaking into the clean hyphenated titles inside theprofile-templates.phpview. - Dynamic Payment Statuses — Replaced Bidspirit's default/cached
NOT PAIDHTML payloads by wiring thedompdfgenerator to directly respect the current$b.statusstring from the API (resolving instances where a paid invoice still printed "NOT PAID" atop the document). - Payment Instructions Conditional — Automatically hide the "Payment Instructions" block from the PDF footer when an invoice is fully paid.
- Improved Nomenclature — Changed "Invoice No:" to "Bidder No:" on document output to prevent confusion with static invoice ledger IDs.
---
[3.2.6.0] — 2026-03-28
Multi-Day Auction Lot Filtering Fix
Fixes
- Day 2+ showing lots from Day 1 in multi-day auctions — The
itemIndexcolumn inbp_meta_dataisvarchar(55), but the day-range filter inBidspiritQuery::bp_query_where()was comparing it as a string. With string comparison, lot numbers like'11','101'–'145'incorrectly fell between'1001'and'1450', causing Day 1 lots to leak into Day 2 results. Fixed by usingCAST(bpMeta.itemIndex AS UNSIGNED)for numeric comparison andintval()on the PHP-side boundary values. Letter lots (e.g.14A,1025A) are handled correctly —CASTstrips the suffix, keeping them grouped with their base lot number.
Files Changed
- Modified:
inc/controllers/BidspiritQuery.php
---
[3.2.5.9] — 2026-03-27
Catalog Page Fix
Fixes
- Duplicate preview hours on catalog pages — The
displayHoursfield was rendered twice: once via thebp_after_description_auctionhook inBidspiritViews.phpand once inline in the auction template. Removed the hook-based rendering to eliminate the duplication.
Files Changed
- Modified:
inc/controllers/BidspiritViews.php,templates/main/auction.php
---
[3.2.5] — 2026-03-19
Sync Reliability & Stuck Lot Prevention
Fixes
- CATALOG_PUBLISHED webhook now triggers catalog sync — Previously only sent push notifications without syncing lots. When the earlier AUCTION_CATALOG_UPDATED fired before the catalog was ready on BidSpirit, lots were never imported. CATALOG_PUBLISHED now calls
auctionCatalogUpdated()to trigger a full catalog sync when the catalog is actually available. - 0-lot API results now fail instead of silently succeeding — When BidSpirit API returns 0 lots (catalog not yet ready), the sync job now fails with an explicit error message, allowing the next webhook to create a fresh retry job.
- Expanded CDN allowlist in pre_http_request filter — The HTTP filter during bulk post insertion now allows all
*.bidspirit.comsubdomains and BidSpirit image CDNs (fastly.net,cloudfront.net). Previously onlybidspirit.comandwww.bidspirit.comwere allowed, blocking image downloads during sync and causing worker hangs. - InsertLotsBS timeout guard — Stage 5 (InsertLotsBS processing loop) now has a 180-second timeout and logs progress every 2 batches. Prevents indefinite hangs that previously required manual force-kill.
- fixResult() no longer marks lots as done when postId=0 — When
lotProcessing()fails to create a WP post, the staging row now keepssyncFinished=0so the lot is retried on the next sync pass, instead of being permanently marked as complete with no actual post. - lotProcessing() logs error on missing auction term — Previously returned 0 silently when
Auction::findAuctionById()failed. Now logs an explicit error that feeds intofixResult()to keep the lot retryable. - Hourly orphan detection in safety cron — New step in
syncSafety.phpdetects lot posts that exist inbp_meta_databut are missing their auction taxonomy assignment (caused by workers killed mid-batch) and auto-repairs them withwp_set_object_terms().
Files Changed
- Modified:
inc/controllers/AuctionsAPI.php,inc/sync/CatalogSyncWorker.php,inc/abs/InsertLotsAbstract.php,inc/import/InsertLotsBS.php,crontasks/syncSafety.php
---
[3.2.4] — 2026-03-18
Sync Worker Hang Fix
Fixes
- Sync workers hanging at InsertLotsBS stage — Third-party plugins (Smush Pro, SmartCrawl SEO, WPMU DEV Updates) hook into
wp_insert_post()and make blocking outbound HTTPS calls for every lot processed. With 489+ lots per auction, this caused workers to hang indefinitely on socket reads to WPMU DEV servers (32.193.94.25,32.193.93.106). AddedWP_IMPORTINGconstant at the REST worker entry point and apre_http_requestfilter inCatalogSyncWorkerthat blocks all non-essential external HTTP during the batch post-insertion phase. Loopback (127.0.0.1,localhost) and BidSpirit API calls remain allowed. - Stuck staging rows after force-kill — When workers were force-killed mid-sync, staging rows in
import_historywere left withsyncstart=1and never unblocked. Subsequent sync runs could not see these rows (filtered out byLot::getRawLots()), causing the InsertLotsBS loop to exit immediately with 0 posts processed. Combined with job deduplication (SyncQueue::enqueue()skips if aprocessingjob exists), this created a deadlock where no new sync could proceed.
Files Changed
- Modified:
auctionforge.php,inc/sync/CatalogSyncWorker.php
---
[3.2.2] — 2026-03-17
Full Sync Auction Discovery Fix
Fixes
- Full Sync finds no auctions on fresh sites — The v3
full_syncaction only queried the WordPress database for existing auction terms, but on a freshly deployed site the database has zero auctions. AddedAuctionList::init()discovery step before querying the DB, so Full Sync now fetches all auctions from the BidSpirit API and creates taxonomy terms first, then enqueues catalog sync jobs for each.
Files Changed
- Modified:
auctionforge.php
---
[3.2.0] — 2026-03-14
Webhook Pipeline Fixes, Archive Sync & Admin UI Overhaul
New Features
- Archive Sync — New "Archive Sync" button on Sync Status admin page. Enqueues catalog sync jobs for all ARCHIVED/ENDED auctions. Past auctions now appear in the auction dropdown with an optgroup separator and state label.
- Sync Tasks v3 — Replaced old v2 task cards (importData, importBidSpirit, lotBidSpiritOld) with v3 queue-based tasks. "Sync Active Auctions" and "Sync Archived Auctions" now enqueue jobs via the queue system. Maintenance tasks (Clean Draft/Trash Lots, Clean Orphaned Meta) remain as direct-execution tasks.
- How It Works guide rewritten — Complete rewrite of the admin guide for v3 architecture. Documents webhook-first flow, all 5 job types, queue system mechanics, cron setup (external + WP-Cron), configuration constants, and troubleshooting.
Fixes
- Dual-write removed — Removed legacy handlers from
auctionCatalogUpdated(),auctionDayEnded(), anditemsUpdated()webhook methods. The old handlers were racing with the v3 worker, creating orphaned staging rows inimport_historythat were never processed. All three methods now exclusively use the v3 enqueue → spawn path. - ITEMS_UPDATED webhook — Fixed
itemsUpdated()failing to enqueue jobs. TheITEMS_UPDATEDpayload hasauctionIdnested initemsByLanguage.{lang}[0].item.auctionId, not at the top level. Added extraction logic to resolve it. - ItemUpdateWorker incomplete —
ItemUpdateWorker::process()was only callingLot::bulkSave()(staging table) without runningInsertLotsBSto process staged data into WP posts andbp_meta_data. Added the InsertLotsBS processing step with autocommit restore. Item updates now flow: stage → InsertLotsBS → WP post + meta → cache clear. - Worker spawn reliability — Changed
SyncQueue::spawnWorker()from non-blocking HTTPS to blocking HTTP loopback (http://127.0.0.1with explicitHostheader, 2s timeout). Fixes nginx 403/404 errors when HTTPS loopback hits the default vhost instead of the site's vhost. - API token constant — Plugin expects
AUCTIONFORGE_API_TOKENinwp-config.php(renamed fromUCO_API_TOKENduring the plugin rename). Documented in readme.
Database
- DB version: 22 → 23
Files Changed
- Modified:
inc/controllers/AuctionsAPI.php,inc/sync/ItemUpdateWorker.php,inc/sync/SyncQueue.php,auctionforge.php,admin/view/sync-status.php,readme.txt
---
[3.0.0] — 2025-03-14
New Feature: Webhook-First Sync Architecture (Sync v3)
Overview: Complete redesign of the BidSpirit data synchronisation pipeline. Replaces the old two-phase polling system (importBidSpirit every hour + importData every minute) with a webhook-driven job queue that processes data in near real-time.
Architecture
- 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: webhook → queue → background worker → WordPress posts. - Dual-write mode — During transition, webhooks enqueue jobs AND still run the legacy handlers. Once verified, legacy handlers can be removed cleanly.
- Job deduplication — Prevents duplicate work by checking for existing pending/processing jobs with the same auction_id + job_type.
New Components
- Job Queue System (
inc/sync/SyncQueue.php) — Priority-based FIFO queue with atomic job claiming, status tracking (pending/processing/completed/failed/skipped), worker PID tracking, and automatic stuck job recovery. - Sync Logger (
inc/sync/SyncLogger.php) — Real-time log table for admin console polling with level filtering (info/success/warning/error) and incremental cursor-based retrieval. - Catalog Sync Worker (
inc/sync/CatalogSyncWorker.php) — Processes catalog_sync, full_sync, and day_ended jobs by reusing existingLotList::singleRun()logic. - Item Update Worker (
inc/sync/ItemUpdateWorker.php) — Processes individual item_update jobs with the same logic as the webhookitemsUpdatedhandler. - Background Worker (
crontasks/syncWorker.php) — Async CLI process spawned by webhooks viaexec()or by the safety cron. Claims and processes queued jobs with a configurable timeout (default 240s). - Safety Net (
crontasks/syncSafety.php) — Hourly cron that resets stuck jobs (>10min), spawns workers for pending jobs, runs a 24-hour health check (auto-enqueues full sync if no webhooks received), and purges old data.
Admin UI
- Queue Status Dashboard — New card on Sync Status page showing pending/processing/completed/failed/skipped counts, recent jobs table with real-time refresh, worker status badge, and action buttons:
- Full Sync — Enqueues catalog sync for all active auctions
- Sync Selected — Enqueue a single auction from dropdown
- Spawn Worker — Manually trigger a background worker process
- Live Console — Dark-themed terminal console on the Sync Status page. Polls
af_sync_logevery 1.5s showing timestamped, color-coded log entries from webhooks, workers, queue operations, and the safety cron. Supports pause, clear, and auto-scroll.
Cron Changes
- Removed
importData(ran every minute — ~1,440 PHP executions/day) - Removed
importBidSpirit(ran hourly — ~24 PHP executions/day) - Added
syncSafety(runs hourly at :10 — 24 PHP executions/day) - Net effect: ~62 PHP executions/hour → 1 PHP execution/hour
- WP-Cron safety hook (
auctionforge_sync_safety) — Always-active hourly event, independent of external cron - setup.sh v3 — Updated task definitions, new
migratecommand for interactive v2→v3 transition
Database
- New table:
af_sync_queue— Job queue with status, priority, source, attempts, worker PID, timing columns - New table:
af_sync_log— Real-time log entries with context, level, auction_id, job_id - DB version: 20 → 22
Constants Added
| Constant | Default | Description |
|---|---|---|
|
AUCTIONFORGE_SYNC_WORKER_TIMEOUT| 240 | Worker process timeout in seconds ||
AUCTIONFORGE_SYNC_STALE_JOB| 600 | Seconds before a processing job is considered stuck ||
AUCTIONFORGE_SYNC_HEALTH_CHECK| 86400 | Seconds without webhook before triggering full sync ||
AUCTIONFORGE_SYNC_LOG_RETENTION| 7 | Days to keep log entries ||
AUCTIONFORGE_SYNC_QUEUE_RETENTION| 30 | Days to keep completed queue jobs ||
AUCTIONFORGE_CURL_TIMEOUT| 30 | BidSpirit API cURL timeout in seconds ||
AUCTIONFORGE_PHP_BINARY| /www/server/php/83/bin/php | PHP CLI binary path for spawning workers |AJAX Handlers Added
auctionforge_sync_log_poll— Incremental log polling for live consoleauctionforge_sync_queue_status— Queue counts + recent jobs for dashboardauctionforge_sync_enqueue— Admin-triggered sync actions (full_sync, sync_auction, spawn_worker)
Fixes
- cURL timeout — BidSpiritRequest now enforces a 30-second timeout (was unlimited/0), preventing hung connections from blocking the sync pipeline.
Files Changed
- Modified:
auctionforge.php,inc/coreIncludes.php,inc/controllers/AuctionsAPI.php,inc/BidSpiritRequest.php,admin/view/sync-status.php,crontasks/setup.sh - Created:
inc/sync/SyncQueue.php,inc/sync/SyncLogger.php,inc/sync/CatalogSyncWorker.php,inc/sync/ItemUpdateWorker.php,crontasks/syncWorker.php,crontasks/syncSafety.php
---
[2.7.3.0]
Fixes
- Various stability improvements and bug fixes.
[2.7.1.2]
Fixes
- Added missing
vatAndCommission()function inloadBid()— the sales tax display on single lot pages was never being rendered because the code to callloadTemplateforvat-and-commission-templatewas missing fromapp.js.
[2.7.1.1]
Fixes
- 2 decimal places now only appear in the bid modal (Your max bid, Total Price) via
showDecimalsflag. 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.
[2.7.0.9]
Fixes
- Fixed fatal error during plugin install/upgrade:
class-stats-database.phprequire failure.
[2.7.0.0]
New Features: Advanced Lot Analytics
- Conversion Tracking, Peak Viewing Times, Pre-Sale vs Live Comparison, Category Performance, Share Analytics, Search → View Funnel, Click-Through Tracking, CSV Export, Hot Lot Badge.
- New DB table:
af_lot_shares. New columns onaf_lot_analytics. DB version bumped to 20.
[2.6.0.0]
New Feature: Lot Analytics
- Comprehensive lot view and favorite tracking system with admin dashboard.
[2.5.0.0]
New Features
- Site Statistics System — Full website analytics built into the plugin admin.
- Recently Viewed Items — Profile page tab showing last 20 viewed lots per user.
- Timed Auction Badge Visibility — Fixed a strict type-matching bug in the main
-
v3.5.0.1 Stable Apr 08, 2026Download v3.5.0.1📦 9.15 MB⚙️ WP 5.2+🔧 PHP 7.2+✓ Tested 6.4
AuctionForge Changelog
All notable changes to the AuctionForge plugin are documented in this file.
---
[3.2.9.2] — 2026-03-30
Timed Auction Archive Fix
Fixes
- Timed Auction Badge Visibility — Fixed a strict type-matching bug in the main
auction_list.phpcore file that incorrectly hid the "Timed Auction" badge overlay from valid timed/online auctions on the main upcoming/archive views. The badge now displays properly across all manual and Bidspirit-synced objects when toggled on.
Files Changed
- Modified:
templates/main/auction_list.php
---
[3.2.9.1] — 2026-03-30
Timed Auction Display Enhancements
Features
- Timed Auction Countdown Text Toggle — Added a WP-Admin setting "Change text to 'Auction will close in'" that conditionally changes the countdown label for timed/online auctions on single lot pages.
- Shortcode Text Toggle Support — Extended the new countdown text logic to the
bp_upcoming_wideshortcodes so "Live bidding starts in:" successfully transitions to "Auction will close in:" for timed auctions.
Files Changed
- Modified:
inc/controllers/Settings.php,templates/single-lot.php,templates/shortcodes/upcoming-auction-wide.php,templates/shortcodes/upcoming-auction-wide-manual.php
---
[3.2.9.0] — 2026-03-29
Billing & Invoices Polish
Fixes
- Profile Invoice ID Tracking — Prevented internal auction codes (e.g.
002orai4) from breaking into the clean hyphenated titles inside theprofile-templates.phpview. - Dynamic Payment Statuses — Replaced Bidspirit's default/cached
NOT PAIDHTML payloads by wiring thedompdfgenerator to directly respect the current$b.statusstring from the API (resolving instances where a paid invoice still printed "NOT PAID" atop the document). - Payment Instructions Conditional — Automatically hide the "Payment Instructions" block from the PDF footer when an invoice is fully paid.
- Improved Nomenclature — Changed "Invoice No:" to "Bidder No:" on document output to prevent confusion with static invoice ledger IDs.
---
[3.2.6.0] — 2026-03-28
Multi-Day Auction Lot Filtering Fix
Fixes
- Day 2+ showing lots from Day 1 in multi-day auctions — The
itemIndexcolumn inbp_meta_dataisvarchar(55), but the day-range filter inBidspiritQuery::bp_query_where()was comparing it as a string. With string comparison, lot numbers like'11','101'–'145'incorrectly fell between'1001'and'1450', causing Day 1 lots to leak into Day 2 results. Fixed by usingCAST(bpMeta.itemIndex AS UNSIGNED)for numeric comparison andintval()on the PHP-side boundary values. Letter lots (e.g.14A,1025A) are handled correctly —CASTstrips the suffix, keeping them grouped with their base lot number.
Files Changed
- Modified:
inc/controllers/BidspiritQuery.php
---
[3.2.5.9] — 2026-03-27
Catalog Page Fix
Fixes
- Duplicate preview hours on catalog pages — The
displayHoursfield was rendered twice: once via thebp_after_description_auctionhook inBidspiritViews.phpand once inline in the auction template. Removed the hook-based rendering to eliminate the duplication.
Files Changed
- Modified:
inc/controllers/BidspiritViews.php,templates/main/auction.php
---
[3.2.5] — 2026-03-19
Sync Reliability & Stuck Lot Prevention
Fixes
- CATALOG_PUBLISHED webhook now triggers catalog sync — Previously only sent push notifications without syncing lots. When the earlier AUCTION_CATALOG_UPDATED fired before the catalog was ready on BidSpirit, lots were never imported. CATALOG_PUBLISHED now calls
auctionCatalogUpdated()to trigger a full catalog sync when the catalog is actually available. - 0-lot API results now fail instead of silently succeeding — When BidSpirit API returns 0 lots (catalog not yet ready), the sync job now fails with an explicit error message, allowing the next webhook to create a fresh retry job.
- Expanded CDN allowlist in pre_http_request filter — The HTTP filter during bulk post insertion now allows all
*.bidspirit.comsubdomains and BidSpirit image CDNs (fastly.net,cloudfront.net). Previously onlybidspirit.comandwww.bidspirit.comwere allowed, blocking image downloads during sync and causing worker hangs. - InsertLotsBS timeout guard — Stage 5 (InsertLotsBS processing loop) now has a 180-second timeout and logs progress every 2 batches. Prevents indefinite hangs that previously required manual force-kill.
- fixResult() no longer marks lots as done when postId=0 — When
lotProcessing()fails to create a WP post, the staging row now keepssyncFinished=0so the lot is retried on the next sync pass, instead of being permanently marked as complete with no actual post. - lotProcessing() logs error on missing auction term — Previously returned 0 silently when
Auction::findAuctionById()failed. Now logs an explicit error that feeds intofixResult()to keep the lot retryable. - Hourly orphan detection in safety cron — New step in
syncSafety.phpdetects lot posts that exist inbp_meta_databut are missing their auction taxonomy assignment (caused by workers killed mid-batch) and auto-repairs them withwp_set_object_terms().
Files Changed
- Modified:
inc/controllers/AuctionsAPI.php,inc/sync/CatalogSyncWorker.php,inc/abs/InsertLotsAbstract.php,inc/import/InsertLotsBS.php,crontasks/syncSafety.php
---
[3.2.4] — 2026-03-18
Sync Worker Hang Fix
Fixes
- Sync workers hanging at InsertLotsBS stage — Third-party plugins (Smush Pro, SmartCrawl SEO, WPMU DEV Updates) hook into
wp_insert_post()and make blocking outbound HTTPS calls for every lot processed. With 489+ lots per auction, this caused workers to hang indefinitely on socket reads to WPMU DEV servers (32.193.94.25,32.193.93.106). AddedWP_IMPORTINGconstant at the REST worker entry point and apre_http_requestfilter inCatalogSyncWorkerthat blocks all non-essential external HTTP during the batch post-insertion phase. Loopback (127.0.0.1,localhost) and BidSpirit API calls remain allowed. - Stuck staging rows after force-kill — When workers were force-killed mid-sync, staging rows in
import_historywere left withsyncstart=1and never unblocked. Subsequent sync runs could not see these rows (filtered out byLot::getRawLots()), causing the InsertLotsBS loop to exit immediately with 0 posts processed. Combined with job deduplication (SyncQueue::enqueue()skips if aprocessingjob exists), this created a deadlock where no new sync could proceed.
Files Changed
- Modified:
auctionforge.php,inc/sync/CatalogSyncWorker.php
---
[3.2.2] — 2026-03-17
Full Sync Auction Discovery Fix
Fixes
- Full Sync finds no auctions on fresh sites — The v3
full_syncaction only queried the WordPress database for existing auction terms, but on a freshly deployed site the database has zero auctions. AddedAuctionList::init()discovery step before querying the DB, so Full Sync now fetches all auctions from the BidSpirit API and creates taxonomy terms first, then enqueues catalog sync jobs for each.
Files Changed
- Modified:
auctionforge.php
---
[3.2.0] — 2026-03-14
Webhook Pipeline Fixes, Archive Sync & Admin UI Overhaul
New Features
- Archive Sync — New "Archive Sync" button on Sync Status admin page. Enqueues catalog sync jobs for all ARCHIVED/ENDED auctions. Past auctions now appear in the auction dropdown with an optgroup separator and state label.
- Sync Tasks v3 — Replaced old v2 task cards (importData, importBidSpirit, lotBidSpiritOld) with v3 queue-based tasks. "Sync Active Auctions" and "Sync Archived Auctions" now enqueue jobs via the queue system. Maintenance tasks (Clean Draft/Trash Lots, Clean Orphaned Meta) remain as direct-execution tasks.
- How It Works guide rewritten — Complete rewrite of the admin guide for v3 architecture. Documents webhook-first flow, all 5 job types, queue system mechanics, cron setup (external + WP-Cron), configuration constants, and troubleshooting.
Fixes
- Dual-write removed — Removed legacy handlers from
auctionCatalogUpdated(),auctionDayEnded(), anditemsUpdated()webhook methods. The old handlers were racing with the v3 worker, creating orphaned staging rows inimport_historythat were never processed. All three methods now exclusively use the v3 enqueue → spawn path. - ITEMS_UPDATED webhook — Fixed
itemsUpdated()failing to enqueue jobs. TheITEMS_UPDATEDpayload hasauctionIdnested initemsByLanguage.{lang}[0].item.auctionId, not at the top level. Added extraction logic to resolve it. - ItemUpdateWorker incomplete —
ItemUpdateWorker::process()was only callingLot::bulkSave()(staging table) without runningInsertLotsBSto process staged data into WP posts andbp_meta_data. Added the InsertLotsBS processing step with autocommit restore. Item updates now flow: stage → InsertLotsBS → WP post + meta → cache clear. - Worker spawn reliability — Changed
SyncQueue::spawnWorker()from non-blocking HTTPS to blocking HTTP loopback (http://127.0.0.1with explicitHostheader, 2s timeout). Fixes nginx 403/404 errors when HTTPS loopback hits the default vhost instead of the site's vhost. - API token constant — Plugin expects
AUCTIONFORGE_API_TOKENinwp-config.php(renamed fromUCO_API_TOKENduring the plugin rename). Documented in readme.
Database
- DB version: 22 → 23
Files Changed
- Modified:
inc/controllers/AuctionsAPI.php,inc/sync/ItemUpdateWorker.php,inc/sync/SyncQueue.php,auctionforge.php,admin/view/sync-status.php,readme.txt
---
[3.0.0] — 2025-03-14
New Feature: Webhook-First Sync Architecture (Sync v3)
Overview: Complete redesign of the BidSpirit data synchronisation pipeline. Replaces the old two-phase polling system (importBidSpirit every hour + importData every minute) with a webhook-driven job queue that processes data in near real-time.
Architecture
- 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: webhook → queue → background worker → WordPress posts. - Dual-write mode — During transition, webhooks enqueue jobs AND still run the legacy handlers. Once verified, legacy handlers can be removed cleanly.
- Job deduplication — Prevents duplicate work by checking for existing pending/processing jobs with the same auction_id + job_type.
New Components
- Job Queue System (
inc/sync/SyncQueue.php) — Priority-based FIFO queue with atomic job claiming, status tracking (pending/processing/completed/failed/skipped), worker PID tracking, and automatic stuck job recovery. - Sync Logger (
inc/sync/SyncLogger.php) — Real-time log table for admin console polling with level filtering (info/success/warning/error) and incremental cursor-based retrieval. - Catalog Sync Worker (
inc/sync/CatalogSyncWorker.php) — Processes catalog_sync, full_sync, and day_ended jobs by reusing existingLotList::singleRun()logic. - Item Update Worker (
inc/sync/ItemUpdateWorker.php) — Processes individual item_update jobs with the same logic as the webhookitemsUpdatedhandler. - Background Worker (
crontasks/syncWorker.php) — Async CLI process spawned by webhooks viaexec()or by the safety cron. Claims and processes queued jobs with a configurable timeout (default 240s). - Safety Net (
crontasks/syncSafety.php) — Hourly cron that resets stuck jobs (>10min), spawns workers for pending jobs, runs a 24-hour health check (auto-enqueues full sync if no webhooks received), and purges old data.
Admin UI
- Queue Status Dashboard — New card on Sync Status page showing pending/processing/completed/failed/skipped counts, recent jobs table with real-time refresh, worker status badge, and action buttons:
- Full Sync — Enqueues catalog sync for all active auctions
- Sync Selected — Enqueue a single auction from dropdown
- Spawn Worker — Manually trigger a background worker process
- Live Console — Dark-themed terminal console on the Sync Status page. Polls
af_sync_logevery 1.5s showing timestamped, color-coded log entries from webhooks, workers, queue operations, and the safety cron. Supports pause, clear, and auto-scroll.
Cron Changes
- Removed
importData(ran every minute — ~1,440 PHP executions/day) - Removed
importBidSpirit(ran hourly — ~24 PHP executions/day) - Added
syncSafety(runs hourly at :10 — 24 PHP executions/day) - Net effect: ~62 PHP executions/hour → 1 PHP execution/hour
- WP-Cron safety hook (
auctionforge_sync_safety) — Always-active hourly event, independent of external cron - setup.sh v3 — Updated task definitions, new
migratecommand for interactive v2→v3 transition
Database
- New table:
af_sync_queue— Job queue with status, priority, source, attempts, worker PID, timing columns - New table:
af_sync_log— Real-time log entries with context, level, auction_id, job_id - DB version: 20 → 22
Constants Added
| Constant | Default | Description |
|---|---|---|
|
AUCTIONFORGE_SYNC_WORKER_TIMEOUT| 240 | Worker process timeout in seconds ||
AUCTIONFORGE_SYNC_STALE_JOB| 600 | Seconds before a processing job is considered stuck ||
AUCTIONFORGE_SYNC_HEALTH_CHECK| 86400 | Seconds without webhook before triggering full sync ||
AUCTIONFORGE_SYNC_LOG_RETENTION| 7 | Days to keep log entries ||
AUCTIONFORGE_SYNC_QUEUE_RETENTION| 30 | Days to keep completed queue jobs ||
AUCTIONFORGE_CURL_TIMEOUT| 30 | BidSpirit API cURL timeout in seconds ||
AUCTIONFORGE_PHP_BINARY| /www/server/php/83/bin/php | PHP CLI binary path for spawning workers |AJAX Handlers Added
auctionforge_sync_log_poll— Incremental log polling for live consoleauctionforge_sync_queue_status— Queue counts + recent jobs for dashboardauctionforge_sync_enqueue— Admin-triggered sync actions (full_sync, sync_auction, spawn_worker)
Fixes
- cURL timeout — BidSpiritRequest now enforces a 30-second timeout (was unlimited/0), preventing hung connections from blocking the sync pipeline.
Files Changed
- Modified:
auctionforge.php,inc/coreIncludes.php,inc/controllers/AuctionsAPI.php,inc/BidSpiritRequest.php,admin/view/sync-status.php,crontasks/setup.sh - Created:
inc/sync/SyncQueue.php,inc/sync/SyncLogger.php,inc/sync/CatalogSyncWorker.php,inc/sync/ItemUpdateWorker.php,crontasks/syncWorker.php,crontasks/syncSafety.php
---
[2.7.3.0]
Fixes
- Various stability improvements and bug fixes.
[2.7.1.2]
Fixes
- Added missing
vatAndCommission()function inloadBid()— the sales tax display on single lot pages was never being rendered because the code to callloadTemplateforvat-and-commission-templatewas missing fromapp.js.
[2.7.1.1]
Fixes
- 2 decimal places now only appear in the bid modal (Your max bid, Total Price) via
showDecimalsflag. 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.
[2.7.0.9]
Fixes
- Fixed fatal error during plugin install/upgrade:
class-stats-database.phprequire failure.
[2.7.0.0]
New Features: Advanced Lot Analytics
- Conversion Tracking, Peak Viewing Times, Pre-Sale vs Live Comparison, Category Performance, Share Analytics, Search → View Funnel, Click-Through Tracking, CSV Export, Hot Lot Badge.
- New DB table:
af_lot_shares. New columns onaf_lot_analytics. DB version bumped to 20.
[2.6.0.0]
New Feature: Lot Analytics
- Comprehensive lot view and favorite tracking system with admin dashboard.
[2.5.0.0]
New Features
- Site Statistics System — Full website analytics built into the plugin admin.
- Recently Viewed Items — Profile page tab showing last 20 viewed lots per user.
- Timed Auction Badge Visibility — Fixed a strict type-matching bug in the main
-
v3.5.0.0 Stable Apr 08, 2026Download v3.5.0.0📦 9.15 MB⚙️ WP 5.2+🔧 PHP 7.2+✓ Tested 6.4
AuctionForge Changelog
All notable changes to the AuctionForge plugin are documented in this file.
---
[3.2.9.2] — 2026-03-30
Timed Auction Archive Fix
Fixes
- Timed Auction Badge Visibility — Fixed a strict type-matching bug in the main
auction_list.phpcore file that incorrectly hid the "Timed Auction" badge overlay from valid timed/online auctions on the main upcoming/archive views. The badge now displays properly across all manual and Bidspirit-synced objects when toggled on.
Files Changed
- Modified:
templates/main/auction_list.php
---
[3.2.9.1] — 2026-03-30
Timed Auction Display Enhancements
Features
- Timed Auction Countdown Text Toggle — Added a WP-Admin setting "Change text to 'Auction will close in'" that conditionally changes the countdown label for timed/online auctions on single lot pages.
- Shortcode Text Toggle Support — Extended the new countdown text logic to the
bp_upcoming_wideshortcodes so "Live bidding starts in:" successfully transitions to "Auction will close in:" for timed auctions.
Files Changed
- Modified:
inc/controllers/Settings.php,templates/single-lot.php,templates/shortcodes/upcoming-auction-wide.php,templates/shortcodes/upcoming-auction-wide-manual.php
---
[3.2.9.0] — 2026-03-29
Billing & Invoices Polish
Fixes
- Profile Invoice ID Tracking — Prevented internal auction codes (e.g.
002orai4) from breaking into the clean hyphenated titles inside theprofile-templates.phpview. - Dynamic Payment Statuses — Replaced Bidspirit's default/cached
NOT PAIDHTML payloads by wiring thedompdfgenerator to directly respect the current$b.statusstring from the API (resolving instances where a paid invoice still printed "NOT PAID" atop the document). - Payment Instructions Conditional — Automatically hide the "Payment Instructions" block from the PDF footer when an invoice is fully paid.
- Improved Nomenclature — Changed "Invoice No:" to "Bidder No:" on document output to prevent confusion with static invoice ledger IDs.
---
[3.2.6.0] — 2026-03-28
Multi-Day Auction Lot Filtering Fix
Fixes
- Day 2+ showing lots from Day 1 in multi-day auctions — The
itemIndexcolumn inbp_meta_dataisvarchar(55), but the day-range filter inBidspiritQuery::bp_query_where()was comparing it as a string. With string comparison, lot numbers like'11','101'–'145'incorrectly fell between'1001'and'1450', causing Day 1 lots to leak into Day 2 results. Fixed by usingCAST(bpMeta.itemIndex AS UNSIGNED)for numeric comparison andintval()on the PHP-side boundary values. Letter lots (e.g.14A,1025A) are handled correctly —CASTstrips the suffix, keeping them grouped with their base lot number.
Files Changed
- Modified:
inc/controllers/BidspiritQuery.php
---
[3.2.5.9] — 2026-03-27
Catalog Page Fix
Fixes
- Duplicate preview hours on catalog pages — The
displayHoursfield was rendered twice: once via thebp_after_description_auctionhook inBidspiritViews.phpand once inline in the auction template. Removed the hook-based rendering to eliminate the duplication.
Files Changed
- Modified:
inc/controllers/BidspiritViews.php,templates/main/auction.php
---
[3.2.5] — 2026-03-19
Sync Reliability & Stuck Lot Prevention
Fixes
- CATALOG_PUBLISHED webhook now triggers catalog sync — Previously only sent push notifications without syncing lots. When the earlier AUCTION_CATALOG_UPDATED fired before the catalog was ready on BidSpirit, lots were never imported. CATALOG_PUBLISHED now calls
auctionCatalogUpdated()to trigger a full catalog sync when the catalog is actually available. - 0-lot API results now fail instead of silently succeeding — When BidSpirit API returns 0 lots (catalog not yet ready), the sync job now fails with an explicit error message, allowing the next webhook to create a fresh retry job.
- Expanded CDN allowlist in pre_http_request filter — The HTTP filter during bulk post insertion now allows all
*.bidspirit.comsubdomains and BidSpirit image CDNs (fastly.net,cloudfront.net). Previously onlybidspirit.comandwww.bidspirit.comwere allowed, blocking image downloads during sync and causing worker hangs. - InsertLotsBS timeout guard — Stage 5 (InsertLotsBS processing loop) now has a 180-second timeout and logs progress every 2 batches. Prevents indefinite hangs that previously required manual force-kill.
- fixResult() no longer marks lots as done when postId=0 — When
lotProcessing()fails to create a WP post, the staging row now keepssyncFinished=0so the lot is retried on the next sync pass, instead of being permanently marked as complete with no actual post. - lotProcessing() logs error on missing auction term — Previously returned 0 silently when
Auction::findAuctionById()failed. Now logs an explicit error that feeds intofixResult()to keep the lot retryable. - Hourly orphan detection in safety cron — New step in
syncSafety.phpdetects lot posts that exist inbp_meta_databut are missing their auction taxonomy assignment (caused by workers killed mid-batch) and auto-repairs them withwp_set_object_terms().
Files Changed
- Modified:
inc/controllers/AuctionsAPI.php,inc/sync/CatalogSyncWorker.php,inc/abs/InsertLotsAbstract.php,inc/import/InsertLotsBS.php,crontasks/syncSafety.php
---
[3.2.4] — 2026-03-18
Sync Worker Hang Fix
Fixes
- Sync workers hanging at InsertLotsBS stage — Third-party plugins (Smush Pro, SmartCrawl SEO, WPMU DEV Updates) hook into
wp_insert_post()and make blocking outbound HTTPS calls for every lot processed. With 489+ lots per auction, this caused workers to hang indefinitely on socket reads to WPMU DEV servers (32.193.94.25,32.193.93.106). AddedWP_IMPORTINGconstant at the REST worker entry point and apre_http_requestfilter inCatalogSyncWorkerthat blocks all non-essential external HTTP during the batch post-insertion phase. Loopback (127.0.0.1,localhost) and BidSpirit API calls remain allowed. - Stuck staging rows after force-kill — When workers were force-killed mid-sync, staging rows in
import_historywere left withsyncstart=1and never unblocked. Subsequent sync runs could not see these rows (filtered out byLot::getRawLots()), causing the InsertLotsBS loop to exit immediately with 0 posts processed. Combined with job deduplication (SyncQueue::enqueue()skips if aprocessingjob exists), this created a deadlock where no new sync could proceed.
Files Changed
- Modified:
auctionforge.php,inc/sync/CatalogSyncWorker.php
---
[3.2.2] — 2026-03-17
Full Sync Auction Discovery Fix
Fixes
- Full Sync finds no auctions on fresh sites — The v3
full_syncaction only queried the WordPress database for existing auction terms, but on a freshly deployed site the database has zero auctions. AddedAuctionList::init()discovery step before querying the DB, so Full Sync now fetches all auctions from the BidSpirit API and creates taxonomy terms first, then enqueues catalog sync jobs for each.
Files Changed
- Modified:
auctionforge.php
---
[3.2.0] — 2026-03-14
Webhook Pipeline Fixes, Archive Sync & Admin UI Overhaul
New Features
- Archive Sync — New "Archive Sync" button on Sync Status admin page. Enqueues catalog sync jobs for all ARCHIVED/ENDED auctions. Past auctions now appear in the auction dropdown with an optgroup separator and state label.
- Sync Tasks v3 — Replaced old v2 task cards (importData, importBidSpirit, lotBidSpiritOld) with v3 queue-based tasks. "Sync Active Auctions" and "Sync Archived Auctions" now enqueue jobs via the queue system. Maintenance tasks (Clean Draft/Trash Lots, Clean Orphaned Meta) remain as direct-execution tasks.
- How It Works guide rewritten — Complete rewrite of the admin guide for v3 architecture. Documents webhook-first flow, all 5 job types, queue system mechanics, cron setup (external + WP-Cron), configuration constants, and troubleshooting.
Fixes
- Dual-write removed — Removed legacy handlers from
auctionCatalogUpdated(),auctionDayEnded(), anditemsUpdated()webhook methods. The old handlers were racing with the v3 worker, creating orphaned staging rows inimport_historythat were never processed. All three methods now exclusively use the v3 enqueue → spawn path. - ITEMS_UPDATED webhook — Fixed
itemsUpdated()failing to enqueue jobs. TheITEMS_UPDATEDpayload hasauctionIdnested initemsByLanguage.{lang}[0].item.auctionId, not at the top level. Added extraction logic to resolve it. - ItemUpdateWorker incomplete —
ItemUpdateWorker::process()was only callingLot::bulkSave()(staging table) without runningInsertLotsBSto process staged data into WP posts andbp_meta_data. Added the InsertLotsBS processing step with autocommit restore. Item updates now flow: stage → InsertLotsBS → WP post + meta → cache clear. - Worker spawn reliability — Changed
SyncQueue::spawnWorker()from non-blocking HTTPS to blocking HTTP loopback (http://127.0.0.1with explicitHostheader, 2s timeout). Fixes nginx 403/404 errors when HTTPS loopback hits the default vhost instead of the site's vhost. - API token constant — Plugin expects
AUCTIONFORGE_API_TOKENinwp-config.php(renamed fromUCO_API_TOKENduring the plugin rename). Documented in readme.
Database
- DB version: 22 → 23
Files Changed
- Modified:
inc/controllers/AuctionsAPI.php,inc/sync/ItemUpdateWorker.php,inc/sync/SyncQueue.php,auctionforge.php,admin/view/sync-status.php,readme.txt
---
[3.0.0] — 2025-03-14
New Feature: Webhook-First Sync Architecture (Sync v3)
Overview: Complete redesign of the BidSpirit data synchronisation pipeline. Replaces the old two-phase polling system (importBidSpirit every hour + importData every minute) with a webhook-driven job queue that processes data in near real-time.
Architecture
- 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: webhook → queue → background worker → WordPress posts. - Dual-write mode — During transition, webhooks enqueue jobs AND still run the legacy handlers. Once verified, legacy handlers can be removed cleanly.
- Job deduplication — Prevents duplicate work by checking for existing pending/processing jobs with the same auction_id + job_type.
New Components
- Job Queue System (
inc/sync/SyncQueue.php) — Priority-based FIFO queue with atomic job claiming, status tracking (pending/processing/completed/failed/skipped), worker PID tracking, and automatic stuck job recovery. - Sync Logger (
inc/sync/SyncLogger.php) — Real-time log table for admin console polling with level filtering (info/success/warning/error) and incremental cursor-based retrieval. - Catalog Sync Worker (
inc/sync/CatalogSyncWorker.php) — Processes catalog_sync, full_sync, and day_ended jobs by reusing existingLotList::singleRun()logic. - Item Update Worker (
inc/sync/ItemUpdateWorker.php) — Processes individual item_update jobs with the same logic as the webhookitemsUpdatedhandler. - Background Worker (
crontasks/syncWorker.php) — Async CLI process spawned by webhooks viaexec()or by the safety cron. Claims and processes queued jobs with a configurable timeout (default 240s). - Safety Net (
crontasks/syncSafety.php) — Hourly cron that resets stuck jobs (>10min), spawns workers for pending jobs, runs a 24-hour health check (auto-enqueues full sync if no webhooks received), and purges old data.
Admin UI
- Queue Status Dashboard — New card on Sync Status page showing pending/processing/completed/failed/skipped counts, recent jobs table with real-time refresh, worker status badge, and action buttons:
- Full Sync — Enqueues catalog sync for all active auctions
- Sync Selected — Enqueue a single auction from dropdown
- Spawn Worker — Manually trigger a background worker process
- Live Console — Dark-themed terminal console on the Sync Status page. Polls
af_sync_logevery 1.5s showing timestamped, color-coded log entries from webhooks, workers, queue operations, and the safety cron. Supports pause, clear, and auto-scroll.
Cron Changes
- Removed
importData(ran every minute — ~1,440 PHP executions/day) - Removed
importBidSpirit(ran hourly — ~24 PHP executions/day) - Added
syncSafety(runs hourly at :10 — 24 PHP executions/day) - Net effect: ~62 PHP executions/hour → 1 PHP execution/hour
- WP-Cron safety hook (
auctionforge_sync_safety) — Always-active hourly event, independent of external cron - setup.sh v3 — Updated task definitions, new
migratecommand for interactive v2→v3 transition
Database
- New table:
af_sync_queue— Job queue with status, priority, source, attempts, worker PID, timing columns - New table:
af_sync_log— Real-time log entries with context, level, auction_id, job_id - DB version: 20 → 22
Constants Added
| Constant | Default | Description |
|---|---|---|
|
AUCTIONFORGE_SYNC_WORKER_TIMEOUT| 240 | Worker process timeout in seconds ||
AUCTIONFORGE_SYNC_STALE_JOB| 600 | Seconds before a processing job is considered stuck ||
AUCTIONFORGE_SYNC_HEALTH_CHECK| 86400 | Seconds without webhook before triggering full sync ||
AUCTIONFORGE_SYNC_LOG_RETENTION| 7 | Days to keep log entries ||
AUCTIONFORGE_SYNC_QUEUE_RETENTION| 30 | Days to keep completed queue jobs ||
AUCTIONFORGE_CURL_TIMEOUT| 30 | BidSpirit API cURL timeout in seconds ||
AUCTIONFORGE_PHP_BINARY| /www/server/php/83/bin/php | PHP CLI binary path for spawning workers |AJAX Handlers Added
auctionforge_sync_log_poll— Incremental log polling for live consoleauctionforge_sync_queue_status— Queue counts + recent jobs for dashboardauctionforge_sync_enqueue— Admin-triggered sync actions (full_sync, sync_auction, spawn_worker)
Fixes
- cURL timeout — BidSpiritRequest now enforces a 30-second timeout (was unlimited/0), preventing hung connections from blocking the sync pipeline.
Files Changed
- Modified:
auctionforge.php,inc/coreIncludes.php,inc/controllers/AuctionsAPI.php,inc/BidSpiritRequest.php,admin/view/sync-status.php,crontasks/setup.sh - Created:
inc/sync/SyncQueue.php,inc/sync/SyncLogger.php,inc/sync/CatalogSyncWorker.php,inc/sync/ItemUpdateWorker.php,crontasks/syncWorker.php,crontasks/syncSafety.php
---
[2.7.3.0]
Fixes
- Various stability improvements and bug fixes.
[2.7.1.2]
Fixes
- Added missing
vatAndCommission()function inloadBid()— the sales tax display on single lot pages was never being rendered because the code to callloadTemplateforvat-and-commission-templatewas missing fromapp.js.
[2.7.1.1]
Fixes
- 2 decimal places now only appear in the bid modal (Your max bid, Total Price) via
showDecimalsflag. 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.
[2.7.0.9]
Fixes
- Fixed fatal error during plugin install/upgrade:
class-stats-database.phprequire failure.
[2.7.0.0]
New Features: Advanced Lot Analytics
- Conversion Tracking, Peak Viewing Times, Pre-Sale vs Live Comparison, Category Performance, Share Analytics, Search → View Funnel, Click-Through Tracking, CSV Export, Hot Lot Badge.
- New DB table:
af_lot_shares. New columns onaf_lot_analytics. DB version bumped to 20.
[2.6.0.0]
New Feature: Lot Analytics
- Comprehensive lot view and favorite tracking system with admin dashboard.
[2.5.0.0]
New Features
- Site Statistics System — Full website analytics built into the plugin admin.
- Recently Viewed Items — Profile page tab showing last 20 viewed lots per user.
- Timed Auction Badge Visibility — Fixed a strict type-matching bug in the main
-
v3.4.0.0 Stable Apr 08, 2026Download v3.4.0.0📦 9.08 MB⚙️ WP 5.2+🔧 PHP 7.2+✓ Tested 6.4
AuctionForge Changelog
All notable changes to the AuctionForge plugin are documented in this file.
---
[3.2.9.2] — 2026-03-30
Timed Auction Archive Fix
Fixes
- Timed Auction Badge Visibility — Fixed a strict type-matching bug in the main
auction_list.phpcore file that incorrectly hid the "Timed Auction" badge overlay from valid timed/online auctions on the main upcoming/archive views. The badge now displays properly across all manual and Bidspirit-synced objects when toggled on.
Files Changed
- Modified:
templates/main/auction_list.php
---
[3.2.9.1] — 2026-03-30
Timed Auction Display Enhancements
Features
- Timed Auction Countdown Text Toggle — Added a WP-Admin setting "Change text to 'Auction will close in'" that conditionally changes the countdown label for timed/online auctions on single lot pages.
- Shortcode Text Toggle Support — Extended the new countdown text logic to the
bp_upcoming_wideshortcodes so "Live bidding starts in:" successfully transitions to "Auction will close in:" for timed auctions.
Files Changed
- Modified:
inc/controllers/Settings.php,templates/single-lot.php,templates/shortcodes/upcoming-auction-wide.php,templates/shortcodes/upcoming-auction-wide-manual.php
---
[3.2.9.0] — 2026-03-29
Billing & Invoices Polish
Fixes
- Profile Invoice ID Tracking — Prevented internal auction codes (e.g.
002orai4) from breaking into the clean hyphenated titles inside theprofile-templates.phpview. - Dynamic Payment Statuses — Replaced Bidspirit's default/cached
NOT PAIDHTML payloads by wiring thedompdfgenerator to directly respect the current$b.statusstring from the API (resolving instances where a paid invoice still printed "NOT PAID" atop the document). - Payment Instructions Conditional — Automatically hide the "Payment Instructions" block from the PDF footer when an invoice is fully paid.
- Improved Nomenclature — Changed "Invoice No:" to "Bidder No:" on document output to prevent confusion with static invoice ledger IDs.
---
[3.2.6.0] — 2026-03-28
Multi-Day Auction Lot Filtering Fix
Fixes
- Day 2+ showing lots from Day 1 in multi-day auctions — The
itemIndexcolumn inbp_meta_dataisvarchar(55), but the day-range filter inBidspiritQuery::bp_query_where()was comparing it as a string. With string comparison, lot numbers like'11','101'–'145'incorrectly fell between'1001'and'1450', causing Day 1 lots to leak into Day 2 results. Fixed by usingCAST(bpMeta.itemIndex AS UNSIGNED)for numeric comparison andintval()on the PHP-side boundary values. Letter lots (e.g.14A,1025A) are handled correctly —CASTstrips the suffix, keeping them grouped with their base lot number.
Files Changed
- Modified:
inc/controllers/BidspiritQuery.php
---
[3.2.5.9] — 2026-03-27
Catalog Page Fix
Fixes
- Duplicate preview hours on catalog pages — The
displayHoursfield was rendered twice: once via thebp_after_description_auctionhook inBidspiritViews.phpand once inline in the auction template. Removed the hook-based rendering to eliminate the duplication.
Files Changed
- Modified:
inc/controllers/BidspiritViews.php,templates/main/auction.php
---
[3.2.5] — 2026-03-19
Sync Reliability & Stuck Lot Prevention
Fixes
- CATALOG_PUBLISHED webhook now triggers catalog sync — Previously only sent push notifications without syncing lots. When the earlier AUCTION_CATALOG_UPDATED fired before the catalog was ready on BidSpirit, lots were never imported. CATALOG_PUBLISHED now calls
auctionCatalogUpdated()to trigger a full catalog sync when the catalog is actually available. - 0-lot API results now fail instead of silently succeeding — When BidSpirit API returns 0 lots (catalog not yet ready), the sync job now fails with an explicit error message, allowing the next webhook to create a fresh retry job.
- Expanded CDN allowlist in pre_http_request filter — The HTTP filter during bulk post insertion now allows all
*.bidspirit.comsubdomains and BidSpirit image CDNs (fastly.net,cloudfront.net). Previously onlybidspirit.comandwww.bidspirit.comwere allowed, blocking image downloads during sync and causing worker hangs. - InsertLotsBS timeout guard — Stage 5 (InsertLotsBS processing loop) now has a 180-second timeout and logs progress every 2 batches. Prevents indefinite hangs that previously required manual force-kill.
- fixResult() no longer marks lots as done when postId=0 — When
lotProcessing()fails to create a WP post, the staging row now keepssyncFinished=0so the lot is retried on the next sync pass, instead of being permanently marked as complete with no actual post. - lotProcessing() logs error on missing auction term — Previously returned 0 silently when
Auction::findAuctionById()failed. Now logs an explicit error that feeds intofixResult()to keep the lot retryable. - Hourly orphan detection in safety cron — New step in
syncSafety.phpdetects lot posts that exist inbp_meta_databut are missing their auction taxonomy assignment (caused by workers killed mid-batch) and auto-repairs them withwp_set_object_terms().
Files Changed
- Modified:
inc/controllers/AuctionsAPI.php,inc/sync/CatalogSyncWorker.php,inc/abs/InsertLotsAbstract.php,inc/import/InsertLotsBS.php,crontasks/syncSafety.php
---
[3.2.4] — 2026-03-18
Sync Worker Hang Fix
Fixes
- Sync workers hanging at InsertLotsBS stage — Third-party plugins (Smush Pro, SmartCrawl SEO, WPMU DEV Updates) hook into
wp_insert_post()and make blocking outbound HTTPS calls for every lot processed. With 489+ lots per auction, this caused workers to hang indefinitely on socket reads to WPMU DEV servers (32.193.94.25,32.193.93.106). AddedWP_IMPORTINGconstant at the REST worker entry point and apre_http_requestfilter inCatalogSyncWorkerthat blocks all non-essential external HTTP during the batch post-insertion phase. Loopback (127.0.0.1,localhost) and BidSpirit API calls remain allowed. - Stuck staging rows after force-kill — When workers were force-killed mid-sync, staging rows in
import_historywere left withsyncstart=1and never unblocked. Subsequent sync runs could not see these rows (filtered out byLot::getRawLots()), causing the InsertLotsBS loop to exit immediately with 0 posts processed. Combined with job deduplication (SyncQueue::enqueue()skips if aprocessingjob exists), this created a deadlock where no new sync could proceed.
Files Changed
- Modified:
auctionforge.php,inc/sync/CatalogSyncWorker.php
---
[3.2.2] — 2026-03-17
Full Sync Auction Discovery Fix
Fixes
- Full Sync finds no auctions on fresh sites — The v3
full_syncaction only queried the WordPress database for existing auction terms, but on a freshly deployed site the database has zero auctions. AddedAuctionList::init()discovery step before querying the DB, so Full Sync now fetches all auctions from the BidSpirit API and creates taxonomy terms first, then enqueues catalog sync jobs for each.
Files Changed
- Modified:
auctionforge.php
---
[3.2.0] — 2026-03-14
Webhook Pipeline Fixes, Archive Sync & Admin UI Overhaul
New Features
- Archive Sync — New "Archive Sync" button on Sync Status admin page. Enqueues catalog sync jobs for all ARCHIVED/ENDED auctions. Past auctions now appear in the auction dropdown with an optgroup separator and state label.
- Sync Tasks v3 — Replaced old v2 task cards (importData, importBidSpirit, lotBidSpiritOld) with v3 queue-based tasks. "Sync Active Auctions" and "Sync Archived Auctions" now enqueue jobs via the queue system. Maintenance tasks (Clean Draft/Trash Lots, Clean Orphaned Meta) remain as direct-execution tasks.
- How It Works guide rewritten — Complete rewrite of the admin guide for v3 architecture. Documents webhook-first flow, all 5 job types, queue system mechanics, cron setup (external + WP-Cron), configuration constants, and troubleshooting.
Fixes
- Dual-write removed — Removed legacy handlers from
auctionCatalogUpdated(),auctionDayEnded(), anditemsUpdated()webhook methods. The old handlers were racing with the v3 worker, creating orphaned staging rows inimport_historythat were never processed. All three methods now exclusively use the v3 enqueue → spawn path. - ITEMS_UPDATED webhook — Fixed
itemsUpdated()failing to enqueue jobs. TheITEMS_UPDATEDpayload hasauctionIdnested initemsByLanguage.{lang}[0].item.auctionId, not at the top level. Added extraction logic to resolve it. - ItemUpdateWorker incomplete —
ItemUpdateWorker::process()was only callingLot::bulkSave()(staging table) without runningInsertLotsBSto process staged data into WP posts andbp_meta_data. Added the InsertLotsBS processing step with autocommit restore. Item updates now flow: stage → InsertLotsBS → WP post + meta → cache clear. - Worker spawn reliability — Changed
SyncQueue::spawnWorker()from non-blocking HTTPS to blocking HTTP loopback (http://127.0.0.1with explicitHostheader, 2s timeout). Fixes nginx 403/404 errors when HTTPS loopback hits the default vhost instead of the site's vhost. - API token constant — Plugin expects
AUCTIONFORGE_API_TOKENinwp-config.php(renamed fromUCO_API_TOKENduring the plugin rename). Documented in readme.
Database
- DB version: 22 → 23
Files Changed
- Modified:
inc/controllers/AuctionsAPI.php,inc/sync/ItemUpdateWorker.php,inc/sync/SyncQueue.php,auctionforge.php,admin/view/sync-status.php,readme.txt
---
[3.0.0] — 2025-03-14
New Feature: Webhook-First Sync Architecture (Sync v3)
Overview: Complete redesign of the BidSpirit data synchronisation pipeline. Replaces the old two-phase polling system (importBidSpirit every hour + importData every minute) with a webhook-driven job queue that processes data in near real-time.
Architecture
- 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: webhook → queue → background worker → WordPress posts. - Dual-write mode — During transition, webhooks enqueue jobs AND still run the legacy handlers. Once verified, legacy handlers can be removed cleanly.
- Job deduplication — Prevents duplicate work by checking for existing pending/processing jobs with the same auction_id + job_type.
New Components
- Job Queue System (
inc/sync/SyncQueue.php) — Priority-based FIFO queue with atomic job claiming, status tracking (pending/processing/completed/failed/skipped), worker PID tracking, and automatic stuck job recovery. - Sync Logger (
inc/sync/SyncLogger.php) — Real-time log table for admin console polling with level filtering (info/success/warning/error) and incremental cursor-based retrieval. - Catalog Sync Worker (
inc/sync/CatalogSyncWorker.php) — Processes catalog_sync, full_sync, and day_ended jobs by reusing existingLotList::singleRun()logic. - Item Update Worker (
inc/sync/ItemUpdateWorker.php) — Processes individual item_update jobs with the same logic as the webhookitemsUpdatedhandler. - Background Worker (
crontasks/syncWorker.php) — Async CLI process spawned by webhooks viaexec()or by the safety cron. Claims and processes queued jobs with a configurable timeout (default 240s). - Safety Net (
crontasks/syncSafety.php) — Hourly cron that resets stuck jobs (>10min), spawns workers for pending jobs, runs a 24-hour health check (auto-enqueues full sync if no webhooks received), and purges old data.
Admin UI
- Queue Status Dashboard — New card on Sync Status page showing pending/processing/completed/failed/skipped counts, recent jobs table with real-time refresh, worker status badge, and action buttons:
- Full Sync — Enqueues catalog sync for all active auctions
- Sync Selected — Enqueue a single auction from dropdown
- Spawn Worker — Manually trigger a background worker process
- Live Console — Dark-themed terminal console on the Sync Status page. Polls
af_sync_logevery 1.5s showing timestamped, color-coded log entries from webhooks, workers, queue operations, and the safety cron. Supports pause, clear, and auto-scroll.
Cron Changes
- Removed
importData(ran every minute — ~1,440 PHP executions/day) - Removed
importBidSpirit(ran hourly — ~24 PHP executions/day) - Added
syncSafety(runs hourly at :10 — 24 PHP executions/day) - Net effect: ~62 PHP executions/hour → 1 PHP execution/hour
- WP-Cron safety hook (
auctionforge_sync_safety) — Always-active hourly event, independent of external cron - setup.sh v3 — Updated task definitions, new
migratecommand for interactive v2→v3 transition
Database
- New table:
af_sync_queue— Job queue with status, priority, source, attempts, worker PID, timing columns - New table:
af_sync_log— Real-time log entries with context, level, auction_id, job_id - DB version: 20 → 22
Constants Added
| Constant | Default | Description |
|---|---|---|
|
AUCTIONFORGE_SYNC_WORKER_TIMEOUT| 240 | Worker process timeout in seconds ||
AUCTIONFORGE_SYNC_STALE_JOB| 600 | Seconds before a processing job is considered stuck ||
AUCTIONFORGE_SYNC_HEALTH_CHECK| 86400 | Seconds without webhook before triggering full sync ||
AUCTIONFORGE_SYNC_LOG_RETENTION| 7 | Days to keep log entries ||
AUCTIONFORGE_SYNC_QUEUE_RETENTION| 30 | Days to keep completed queue jobs ||
AUCTIONFORGE_CURL_TIMEOUT| 30 | BidSpirit API cURL timeout in seconds ||
AUCTIONFORGE_PHP_BINARY| /www/server/php/83/bin/php | PHP CLI binary path for spawning workers |AJAX Handlers Added
auctionforge_sync_log_poll— Incremental log polling for live consoleauctionforge_sync_queue_status— Queue counts + recent jobs for dashboardauctionforge_sync_enqueue— Admin-triggered sync actions (full_sync, sync_auction, spawn_worker)
Fixes
- cURL timeout — BidSpiritRequest now enforces a 30-second timeout (was unlimited/0), preventing hung connections from blocking the sync pipeline.
Files Changed
- Modified:
auctionforge.php,inc/coreIncludes.php,inc/controllers/AuctionsAPI.php,inc/BidSpiritRequest.php,admin/view/sync-status.php,crontasks/setup.sh - Created:
inc/sync/SyncQueue.php,inc/sync/SyncLogger.php,inc/sync/CatalogSyncWorker.php,inc/sync/ItemUpdateWorker.php,crontasks/syncWorker.php,crontasks/syncSafety.php
---
[2.7.3.0]
Fixes
- Various stability improvements and bug fixes.
[2.7.1.2]
Fixes
- Added missing
vatAndCommission()function inloadBid()— the sales tax display on single lot pages was never being rendered because the code to callloadTemplateforvat-and-commission-templatewas missing fromapp.js.
[2.7.1.1]
Fixes
- 2 decimal places now only appear in the bid modal (Your max bid, Total Price) via
showDecimalsflag. 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.
[2.7.0.9]
Fixes
- Fixed fatal error during plugin install/upgrade:
class-stats-database.phprequire failure.
[2.7.0.0]
New Features: Advanced Lot Analytics
- Conversion Tracking, Peak Viewing Times, Pre-Sale vs Live Comparison, Category Performance, Share Analytics, Search → View Funnel, Click-Through Tracking, CSV Export, Hot Lot Badge.
- New DB table:
af_lot_shares. New columns onaf_lot_analytics. DB version bumped to 20.
[2.6.0.0]
New Feature: Lot Analytics
- Comprehensive lot view and favorite tracking system with admin dashboard.
[2.5.0.0]
New Features
- Site Statistics System — Full website analytics built into the plugin admin.
- Recently Viewed Items — Profile page tab showing last 20 viewed lots per user.
- Timed Auction Badge Visibility — Fixed a strict type-matching bug in the main
-
v3.3.0.0 Stable Apr 08, 2026Download v3.3.0.0📦 9.08 MB⚙️ WP 6.0+🔧 PHP 8.0+✓ Tested 6.4.3
Added Central Site Statistics Proxy
Added Remote Live Auction Sync Hooks
-
v3.2.9.5 Stable Apr 02, 2026Download v3.2.9.5📦 8.82 MB⚙️ WP 5.2+🔧 PHP 7.2+✓ Tested 6.4
AuctionForge Changelog
All notable changes to the AuctionForge plugin are documented in this file.
---
[3.2.9.2] — 2026-03-30
Timed Auction Archive Fix
Fixes
- Timed Auction Badge Visibility — Fixed a strict type-matching bug in the main
auction_list.phpcore file that incorrectly hid the "Timed Auction" badge overlay from valid timed/online auctions on the main upcoming/archive views. The badge now displays properly across all manual and Bidspirit-synced objects when toggled on.
Files Changed
- Modified:
templates/main/auction_list.php
---
[3.2.9.1] — 2026-03-30
Timed Auction Display Enhancements
Features
- Timed Auction Countdown Text Toggle — Added a WP-Admin setting "Change text to 'Auction will close in'" that conditionally changes the countdown label for timed/online auctions on single lot pages.
- Shortcode Text Toggle Support — Extended the new countdown text logic to the
bp_upcoming_wideshortcodes so "Live bidding starts in:" successfully transitions to "Auction will close in:" for timed auctions.
Files Changed
- Modified:
inc/controllers/Settings.php,templates/single-lot.php,templates/shortcodes/upcoming-auction-wide.php,templates/shortcodes/upcoming-auction-wide-manual.php
---
[3.2.9.0] — 2026-03-29
Billing & Invoices Polish
Fixes
- Profile Invoice ID Tracking — Prevented internal auction codes (e.g.
002orai4) from breaking into the clean hyphenated titles inside theprofile-templates.phpview. - Dynamic Payment Statuses — Replaced Bidspirit's default/cached
NOT PAIDHTML payloads by wiring thedompdfgenerator to directly respect the current$b.statusstring from the API (resolving instances where a paid invoice still printed "NOT PAID" atop the document). - Payment Instructions Conditional — Automatically hide the "Payment Instructions" block from the PDF footer when an invoice is fully paid.
- Improved Nomenclature — Changed "Invoice No:" to "Bidder No:" on document output to prevent confusion with static invoice ledger IDs.
---
[3.2.6.0] — 2026-03-28
Multi-Day Auction Lot Filtering Fix
Fixes
- Day 2+ showing lots from Day 1 in multi-day auctions — The
itemIndexcolumn inbp_meta_dataisvarchar(55), but the day-range filter inBidspiritQuery::bp_query_where()was comparing it as a string. With string comparison, lot numbers like'11','101'–'145'incorrectly fell between'1001'and'1450', causing Day 1 lots to leak into Day 2 results. Fixed by usingCAST(bpMeta.itemIndex AS UNSIGNED)for numeric comparison andintval()on the PHP-side boundary values. Letter lots (e.g.14A,1025A) are handled correctly —CASTstrips the suffix, keeping them grouped with their base lot number.
Files Changed
- Modified:
inc/controllers/BidspiritQuery.php
---
[3.2.5.9] — 2026-03-27
Catalog Page Fix
Fixes
- Duplicate preview hours on catalog pages — The
displayHoursfield was rendered twice: once via thebp_after_description_auctionhook inBidspiritViews.phpand once inline in the auction template. Removed the hook-based rendering to eliminate the duplication.
Files Changed
- Modified:
inc/controllers/BidspiritViews.php,templates/main/auction.php
---
[3.2.5] — 2026-03-19
Sync Reliability & Stuck Lot Prevention
Fixes
- CATALOG_PUBLISHED webhook now triggers catalog sync — Previously only sent push notifications without syncing lots. When the earlier AUCTION_CATALOG_UPDATED fired before the catalog was ready on BidSpirit, lots were never imported. CATALOG_PUBLISHED now calls
auctionCatalogUpdated()to trigger a full catalog sync when the catalog is actually available. - 0-lot API results now fail instead of silently succeeding — When BidSpirit API returns 0 lots (catalog not yet ready), the sync job now fails with an explicit error message, allowing the next webhook to create a fresh retry job.
- Expanded CDN allowlist in pre_http_request filter — The HTTP filter during bulk post insertion now allows all
*.bidspirit.comsubdomains and BidSpirit image CDNs (fastly.net,cloudfront.net). Previously onlybidspirit.comandwww.bidspirit.comwere allowed, blocking image downloads during sync and causing worker hangs. - InsertLotsBS timeout guard — Stage 5 (InsertLotsBS processing loop) now has a 180-second timeout and logs progress every 2 batches. Prevents indefinite hangs that previously required manual force-kill.
- fixResult() no longer marks lots as done when postId=0 — When
lotProcessing()fails to create a WP post, the staging row now keepssyncFinished=0so the lot is retried on the next sync pass, instead of being permanently marked as complete with no actual post. - lotProcessing() logs error on missing auction term — Previously returned 0 silently when
Auction::findAuctionById()failed. Now logs an explicit error that feeds intofixResult()to keep the lot retryable. - Hourly orphan detection in safety cron — New step in
syncSafety.phpdetects lot posts that exist inbp_meta_databut are missing their auction taxonomy assignment (caused by workers killed mid-batch) and auto-repairs them withwp_set_object_terms().
Files Changed
- Modified:
inc/controllers/AuctionsAPI.php,inc/sync/CatalogSyncWorker.php,inc/abs/InsertLotsAbstract.php,inc/import/InsertLotsBS.php,crontasks/syncSafety.php
---
[3.2.4] — 2026-03-18
Sync Worker Hang Fix
Fixes
- Sync workers hanging at InsertLotsBS stage — Third-party plugins (Smush Pro, SmartCrawl SEO, WPMU DEV Updates) hook into
wp_insert_post()and make blocking outbound HTTPS calls for every lot processed. With 489+ lots per auction, this caused workers to hang indefinitely on socket reads to WPMU DEV servers (32.193.94.25,32.193.93.106). AddedWP_IMPORTINGconstant at the REST worker entry point and apre_http_requestfilter inCatalogSyncWorkerthat blocks all non-essential external HTTP during the batch post-insertion phase. Loopback (127.0.0.1,localhost) and BidSpirit API calls remain allowed. - Stuck staging rows after force-kill — When workers were force-killed mid-sync, staging rows in
import_historywere left withsyncstart=1and never unblocked. Subsequent sync runs could not see these rows (filtered out byLot::getRawLots()), causing the InsertLotsBS loop to exit immediately with 0 posts processed. Combined with job deduplication (SyncQueue::enqueue()skips if aprocessingjob exists), this created a deadlock where no new sync could proceed.
Files Changed
- Modified:
auctionforge.php,inc/sync/CatalogSyncWorker.php
---
[3.2.2] — 2026-03-17
Full Sync Auction Discovery Fix
Fixes
- Full Sync finds no auctions on fresh sites — The v3
full_syncaction only queried the WordPress database for existing auction terms, but on a freshly deployed site the database has zero auctions. AddedAuctionList::init()discovery step before querying the DB, so Full Sync now fetches all auctions from the BidSpirit API and creates taxonomy terms first, then enqueues catalog sync jobs for each.
Files Changed
- Modified:
auctionforge.php
---
[3.2.0] — 2026-03-14
Webhook Pipeline Fixes, Archive Sync & Admin UI Overhaul
New Features
- Archive Sync — New "Archive Sync" button on Sync Status admin page. Enqueues catalog sync jobs for all ARCHIVED/ENDED auctions. Past auctions now appear in the auction dropdown with an optgroup separator and state label.
- Sync Tasks v3 — Replaced old v2 task cards (importData, importBidSpirit, lotBidSpiritOld) with v3 queue-based tasks. "Sync Active Auctions" and "Sync Archived Auctions" now enqueue jobs via the queue system. Maintenance tasks (Clean Draft/Trash Lots, Clean Orphaned Meta) remain as direct-execution tasks.
- How It Works guide rewritten — Complete rewrite of the admin guide for v3 architecture. Documents webhook-first flow, all 5 job types, queue system mechanics, cron setup (external + WP-Cron), configuration constants, and troubleshooting.
Fixes
- Dual-write removed — Removed legacy handlers from
auctionCatalogUpdated(),auctionDayEnded(), anditemsUpdated()webhook methods. The old handlers were racing with the v3 worker, creating orphaned staging rows inimport_historythat were never processed. All three methods now exclusively use the v3 enqueue → spawn path. - ITEMS_UPDATED webhook — Fixed
itemsUpdated()failing to enqueue jobs. TheITEMS_UPDATEDpayload hasauctionIdnested initemsByLanguage.{lang}[0].item.auctionId, not at the top level. Added extraction logic to resolve it. - ItemUpdateWorker incomplete —
ItemUpdateWorker::process()was only callingLot::bulkSave()(staging table) without runningInsertLotsBSto process staged data into WP posts andbp_meta_data. Added the InsertLotsBS processing step with autocommit restore. Item updates now flow: stage → InsertLotsBS → WP post + meta → cache clear. - Worker spawn reliability — Changed
SyncQueue::spawnWorker()from non-blocking HTTPS to blocking HTTP loopback (http://127.0.0.1with explicitHostheader, 2s timeout). Fixes nginx 403/404 errors when HTTPS loopback hits the default vhost instead of the site's vhost. - API token constant — Plugin expects
AUCTIONFORGE_API_TOKENinwp-config.php(renamed fromUCO_API_TOKENduring the plugin rename). Documented in readme.
Database
- DB version: 22 → 23
Files Changed
- Modified:
inc/controllers/AuctionsAPI.php,inc/sync/ItemUpdateWorker.php,inc/sync/SyncQueue.php,auctionforge.php,admin/view/sync-status.php,readme.txt
---
[3.0.0] — 2025-03-14
New Feature: Webhook-First Sync Architecture (Sync v3)
Overview: Complete redesign of the BidSpirit data synchronisation pipeline. Replaces the old two-phase polling system (importBidSpirit every hour + importData every minute) with a webhook-driven job queue that processes data in near real-time.
Architecture
- 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: webhook → queue → background worker → WordPress posts. - Dual-write mode — During transition, webhooks enqueue jobs AND still run the legacy handlers. Once verified, legacy handlers can be removed cleanly.
- Job deduplication — Prevents duplicate work by checking for existing pending/processing jobs with the same auction_id + job_type.
New Components
- Job Queue System (
inc/sync/SyncQueue.php) — Priority-based FIFO queue with atomic job claiming, status tracking (pending/processing/completed/failed/skipped), worker PID tracking, and automatic stuck job recovery. - Sync Logger (
inc/sync/SyncLogger.php) — Real-time log table for admin console polling with level filtering (info/success/warning/error) and incremental cursor-based retrieval. - Catalog Sync Worker (
inc/sync/CatalogSyncWorker.php) — Processes catalog_sync, full_sync, and day_ended jobs by reusing existingLotList::singleRun()logic. - Item Update Worker (
inc/sync/ItemUpdateWorker.php) — Processes individual item_update jobs with the same logic as the webhookitemsUpdatedhandler. - Background Worker (
crontasks/syncWorker.php) — Async CLI process spawned by webhooks viaexec()or by the safety cron. Claims and processes queued jobs with a configurable timeout (default 240s). - Safety Net (
crontasks/syncSafety.php) — Hourly cron that resets stuck jobs (>10min), spawns workers for pending jobs, runs a 24-hour health check (auto-enqueues full sync if no webhooks received), and purges old data.
Admin UI
- Queue Status Dashboard — New card on Sync Status page showing pending/processing/completed/failed/skipped counts, recent jobs table with real-time refresh, worker status badge, and action buttons:
- Full Sync — Enqueues catalog sync for all active auctions
- Sync Selected — Enqueue a single auction from dropdown
- Spawn Worker — Manually trigger a background worker process
- Live Console — Dark-themed terminal console on the Sync Status page. Polls
af_sync_logevery 1.5s showing timestamped, color-coded log entries from webhooks, workers, queue operations, and the safety cron. Supports pause, clear, and auto-scroll.
Cron Changes
- Removed
importData(ran every minute — ~1,440 PHP executions/day) - Removed
importBidSpirit(ran hourly — ~24 PHP executions/day) - Added
syncSafety(runs hourly at :10 — 24 PHP executions/day) - Net effect: ~62 PHP executions/hour → 1 PHP execution/hour
- WP-Cron safety hook (
auctionforge_sync_safety) — Always-active hourly event, independent of external cron - setup.sh v3 — Updated task definitions, new
migratecommand for interactive v2→v3 transition
Database
- New table:
af_sync_queue— Job queue with status, priority, source, attempts, worker PID, timing columns - New table:
af_sync_log— Real-time log entries with context, level, auction_id, job_id - DB version: 20 → 22
Constants Added
| Constant | Default | Description |
|---|---|---|
|
AUCTIONFORGE_SYNC_WORKER_TIMEOUT| 240 | Worker process timeout in seconds ||
AUCTIONFORGE_SYNC_STALE_JOB| 600 | Seconds before a processing job is considered stuck ||
AUCTIONFORGE_SYNC_HEALTH_CHECK| 86400 | Seconds without webhook before triggering full sync ||
AUCTIONFORGE_SYNC_LOG_RETENTION| 7 | Days to keep log entries ||
AUCTIONFORGE_SYNC_QUEUE_RETENTION| 30 | Days to keep completed queue jobs ||
AUCTIONFORGE_CURL_TIMEOUT| 30 | BidSpirit API cURL timeout in seconds ||
AUCTIONFORGE_PHP_BINARY| /www/server/php/83/bin/php | PHP CLI binary path for spawning workers |AJAX Handlers Added
auctionforge_sync_log_poll— Incremental log polling for live consoleauctionforge_sync_queue_status— Queue counts + recent jobs for dashboardauctionforge_sync_enqueue— Admin-triggered sync actions (full_sync, sync_auction, spawn_worker)
Fixes
- cURL timeout — BidSpiritRequest now enforces a 30-second timeout (was unlimited/0), preventing hung connections from blocking the sync pipeline.
Files Changed
- Modified:
auctionforge.php,inc/coreIncludes.php,inc/controllers/AuctionsAPI.php,inc/BidSpiritRequest.php,admin/view/sync-status.php,crontasks/setup.sh - Created:
inc/sync/SyncQueue.php,inc/sync/SyncLogger.php,inc/sync/CatalogSyncWorker.php,inc/sync/ItemUpdateWorker.php,crontasks/syncWorker.php,crontasks/syncSafety.php
---
[2.7.3.0]
Fixes
- Various stability improvements and bug fixes.
[2.7.1.2]
Fixes
- Added missing
vatAndCommission()function inloadBid()— the sales tax display on single lot pages was never being rendered because the code to callloadTemplateforvat-and-commission-templatewas missing fromapp.js.
[2.7.1.1]
Fixes
- 2 decimal places now only appear in the bid modal (Your max bid, Total Price) via
showDecimalsflag. 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.
[2.7.0.9]
Fixes
- Fixed fatal error during plugin install/upgrade:
class-stats-database.phprequire failure.
[2.7.0.0]
New Features: Advanced Lot Analytics
- Conversion Tracking, Peak Viewing Times, Pre-Sale vs Live Comparison, Category Performance, Share Analytics, Search → View Funnel, Click-Through Tracking, CSV Export, Hot Lot Badge.
- New DB table:
af_lot_shares. New columns onaf_lot_analytics. DB version bumped to 20.
[2.6.0.0]
New Feature: Lot Analytics
- Comprehensive lot view and favorite tracking system with admin dashboard.
[2.5.0.0]
New Features
- Site Statistics System — Full website analytics built into the plugin admin.
- Recently Viewed Items — Profile page tab showing last 20 viewed lots per user.
- Timed Auction Badge Visibility — Fixed a strict type-matching bug in the main
-
v3.2.9.4 Stable Apr 02, 2026Download v3.2.9.4📦 8.82 MB⚙️ WP 5.2+🔧 PHP 7.2+✓ Tested 6.4
AuctionForge Changelog
All notable changes to the AuctionForge plugin are documented in this file.
---
[3.2.9.2] — 2026-03-30
Timed Auction Archive Fix
Fixes
- Timed Auction Badge Visibility — Fixed a strict type-matching bug in the main
auction_list.phpcore file that incorrectly hid the "Timed Auction" badge overlay from valid timed/online auctions on the main upcoming/archive views. The badge now displays properly across all manual and Bidspirit-synced objects when toggled on.
Files Changed
- Modified:
templates/main/auction_list.php
---
[3.2.9.1] — 2026-03-30
Timed Auction Display Enhancements
Features
- Timed Auction Countdown Text Toggle — Added a WP-Admin setting "Change text to 'Auction will close in'" that conditionally changes the countdown label for timed/online auctions on single lot pages.
- Shortcode Text Toggle Support — Extended the new countdown text logic to the
bp_upcoming_wideshortcodes so "Live bidding starts in:" successfully transitions to "Auction will close in:" for timed auctions.
Files Changed
- Modified:
inc/controllers/Settings.php,templates/single-lot.php,templates/shortcodes/upcoming-auction-wide.php,templates/shortcodes/upcoming-auction-wide-manual.php
---
[3.2.9.0] — 2026-03-29
Billing & Invoices Polish
Fixes
- Profile Invoice ID Tracking — Prevented internal auction codes (e.g.
002orai4) from breaking into the clean hyphenated titles inside theprofile-templates.phpview. - Dynamic Payment Statuses — Replaced Bidspirit's default/cached
NOT PAIDHTML payloads by wiring thedompdfgenerator to directly respect the current$b.statusstring from the API (resolving instances where a paid invoice still printed "NOT PAID" atop the document). - Payment Instructions Conditional — Automatically hide the "Payment Instructions" block from the PDF footer when an invoice is fully paid.
- Improved Nomenclature — Changed "Invoice No:" to "Bidder No:" on document output to prevent confusion with static invoice ledger IDs.
---
[3.2.6.0] — 2026-03-28
Multi-Day Auction Lot Filtering Fix
Fixes
- Day 2+ showing lots from Day 1 in multi-day auctions — The
itemIndexcolumn inbp_meta_dataisvarchar(55), but the day-range filter inBidspiritQuery::bp_query_where()was comparing it as a string. With string comparison, lot numbers like'11','101'–'145'incorrectly fell between'1001'and'1450', causing Day 1 lots to leak into Day 2 results. Fixed by usingCAST(bpMeta.itemIndex AS UNSIGNED)for numeric comparison andintval()on the PHP-side boundary values. Letter lots (e.g.14A,1025A) are handled correctly —CASTstrips the suffix, keeping them grouped with their base lot number.
Files Changed
- Modified:
inc/controllers/BidspiritQuery.php
---
[3.2.5.9] — 2026-03-27
Catalog Page Fix
Fixes
- Duplicate preview hours on catalog pages — The
displayHoursfield was rendered twice: once via thebp_after_description_auctionhook inBidspiritViews.phpand once inline in the auction template. Removed the hook-based rendering to eliminate the duplication.
Files Changed
- Modified:
inc/controllers/BidspiritViews.php,templates/main/auction.php
---
[3.2.5] — 2026-03-19
Sync Reliability & Stuck Lot Prevention
Fixes
- CATALOG_PUBLISHED webhook now triggers catalog sync — Previously only sent push notifications without syncing lots. When the earlier AUCTION_CATALOG_UPDATED fired before the catalog was ready on BidSpirit, lots were never imported. CATALOG_PUBLISHED now calls
auctionCatalogUpdated()to trigger a full catalog sync when the catalog is actually available. - 0-lot API results now fail instead of silently succeeding — When BidSpirit API returns 0 lots (catalog not yet ready), the sync job now fails with an explicit error message, allowing the next webhook to create a fresh retry job.
- Expanded CDN allowlist in pre_http_request filter — The HTTP filter during bulk post insertion now allows all
*.bidspirit.comsubdomains and BidSpirit image CDNs (fastly.net,cloudfront.net). Previously onlybidspirit.comandwww.bidspirit.comwere allowed, blocking image downloads during sync and causing worker hangs. - InsertLotsBS timeout guard — Stage 5 (InsertLotsBS processing loop) now has a 180-second timeout and logs progress every 2 batches. Prevents indefinite hangs that previously required manual force-kill.
- fixResult() no longer marks lots as done when postId=0 — When
lotProcessing()fails to create a WP post, the staging row now keepssyncFinished=0so the lot is retried on the next sync pass, instead of being permanently marked as complete with no actual post. - lotProcessing() logs error on missing auction term — Previously returned 0 silently when
Auction::findAuctionById()failed. Now logs an explicit error that feeds intofixResult()to keep the lot retryable. - Hourly orphan detection in safety cron — New step in
syncSafety.phpdetects lot posts that exist inbp_meta_databut are missing their auction taxonomy assignment (caused by workers killed mid-batch) and auto-repairs them withwp_set_object_terms().
Files Changed
- Modified:
inc/controllers/AuctionsAPI.php,inc/sync/CatalogSyncWorker.php,inc/abs/InsertLotsAbstract.php,inc/import/InsertLotsBS.php,crontasks/syncSafety.php
---
[3.2.4] — 2026-03-18
Sync Worker Hang Fix
Fixes
- Sync workers hanging at InsertLotsBS stage — Third-party plugins (Smush Pro, SmartCrawl SEO, WPMU DEV Updates) hook into
wp_insert_post()and make blocking outbound HTTPS calls for every lot processed. With 489+ lots per auction, this caused workers to hang indefinitely on socket reads to WPMU DEV servers (32.193.94.25,32.193.93.106). AddedWP_IMPORTINGconstant at the REST worker entry point and apre_http_requestfilter inCatalogSyncWorkerthat blocks all non-essential external HTTP during the batch post-insertion phase. Loopback (127.0.0.1,localhost) and BidSpirit API calls remain allowed. - Stuck staging rows after force-kill — When workers were force-killed mid-sync, staging rows in
import_historywere left withsyncstart=1and never unblocked. Subsequent sync runs could not see these rows (filtered out byLot::getRawLots()), causing the InsertLotsBS loop to exit immediately with 0 posts processed. Combined with job deduplication (SyncQueue::enqueue()skips if aprocessingjob exists), this created a deadlock where no new sync could proceed.
Files Changed
- Modified:
auctionforge.php,inc/sync/CatalogSyncWorker.php
---
[3.2.2] — 2026-03-17
Full Sync Auction Discovery Fix
Fixes
- Full Sync finds no auctions on fresh sites — The v3
full_syncaction only queried the WordPress database for existing auction terms, but on a freshly deployed site the database has zero auctions. AddedAuctionList::init()discovery step before querying the DB, so Full Sync now fetches all auctions from the BidSpirit API and creates taxonomy terms first, then enqueues catalog sync jobs for each.
Files Changed
- Modified:
auctionforge.php
---
[3.2.0] — 2026-03-14
Webhook Pipeline Fixes, Archive Sync & Admin UI Overhaul
New Features
- Archive Sync — New "Archive Sync" button on Sync Status admin page. Enqueues catalog sync jobs for all ARCHIVED/ENDED auctions. Past auctions now appear in the auction dropdown with an optgroup separator and state label.
- Sync Tasks v3 — Replaced old v2 task cards (importData, importBidSpirit, lotBidSpiritOld) with v3 queue-based tasks. "Sync Active Auctions" and "Sync Archived Auctions" now enqueue jobs via the queue system. Maintenance tasks (Clean Draft/Trash Lots, Clean Orphaned Meta) remain as direct-execution tasks.
- How It Works guide rewritten — Complete rewrite of the admin guide for v3 architecture. Documents webhook-first flow, all 5 job types, queue system mechanics, cron setup (external + WP-Cron), configuration constants, and troubleshooting.
Fixes
- Dual-write removed — Removed legacy handlers from
auctionCatalogUpdated(),auctionDayEnded(), anditemsUpdated()webhook methods. The old handlers were racing with the v3 worker, creating orphaned staging rows inimport_historythat were never processed. All three methods now exclusively use the v3 enqueue → spawn path. - ITEMS_UPDATED webhook — Fixed
itemsUpdated()failing to enqueue jobs. TheITEMS_UPDATEDpayload hasauctionIdnested initemsByLanguage.{lang}[0].item.auctionId, not at the top level. Added extraction logic to resolve it. - ItemUpdateWorker incomplete —
ItemUpdateWorker::process()was only callingLot::bulkSave()(staging table) without runningInsertLotsBSto process staged data into WP posts andbp_meta_data. Added the InsertLotsBS processing step with autocommit restore. Item updates now flow: stage → InsertLotsBS → WP post + meta → cache clear. - Worker spawn reliability — Changed
SyncQueue::spawnWorker()from non-blocking HTTPS to blocking HTTP loopback (http://127.0.0.1with explicitHostheader, 2s timeout). Fixes nginx 403/404 errors when HTTPS loopback hits the default vhost instead of the site's vhost. - API token constant — Plugin expects
AUCTIONFORGE_API_TOKENinwp-config.php(renamed fromUCO_API_TOKENduring the plugin rename). Documented in readme.
Database
- DB version: 22 → 23
Files Changed
- Modified:
inc/controllers/AuctionsAPI.php,inc/sync/ItemUpdateWorker.php,inc/sync/SyncQueue.php,auctionforge.php,admin/view/sync-status.php,readme.txt
---
[3.0.0] — 2025-03-14
New Feature: Webhook-First Sync Architecture (Sync v3)
Overview: Complete redesign of the BidSpirit data synchronisation pipeline. Replaces the old two-phase polling system (importBidSpirit every hour + importData every minute) with a webhook-driven job queue that processes data in near real-time.
Architecture
- 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: webhook → queue → background worker → WordPress posts. - Dual-write mode — During transition, webhooks enqueue jobs AND still run the legacy handlers. Once verified, legacy handlers can be removed cleanly.
- Job deduplication — Prevents duplicate work by checking for existing pending/processing jobs with the same auction_id + job_type.
New Components
- Job Queue System (
inc/sync/SyncQueue.php) — Priority-based FIFO queue with atomic job claiming, status tracking (pending/processing/completed/failed/skipped), worker PID tracking, and automatic stuck job recovery. - Sync Logger (
inc/sync/SyncLogger.php) — Real-time log table for admin console polling with level filtering (info/success/warning/error) and incremental cursor-based retrieval. - Catalog Sync Worker (
inc/sync/CatalogSyncWorker.php) — Processes catalog_sync, full_sync, and day_ended jobs by reusing existingLotList::singleRun()logic. - Item Update Worker (
inc/sync/ItemUpdateWorker.php) — Processes individual item_update jobs with the same logic as the webhookitemsUpdatedhandler. - Background Worker (
crontasks/syncWorker.php) — Async CLI process spawned by webhooks viaexec()or by the safety cron. Claims and processes queued jobs with a configurable timeout (default 240s). - Safety Net (
crontasks/syncSafety.php) — Hourly cron that resets stuck jobs (>10min), spawns workers for pending jobs, runs a 24-hour health check (auto-enqueues full sync if no webhooks received), and purges old data.
Admin UI
- Queue Status Dashboard — New card on Sync Status page showing pending/processing/completed/failed/skipped counts, recent jobs table with real-time refresh, worker status badge, and action buttons:
- Full Sync — Enqueues catalog sync for all active auctions
- Sync Selected — Enqueue a single auction from dropdown
- Spawn Worker — Manually trigger a background worker process
- Live Console — Dark-themed terminal console on the Sync Status page. Polls
af_sync_logevery 1.5s showing timestamped, color-coded log entries from webhooks, workers, queue operations, and the safety cron. Supports pause, clear, and auto-scroll.
Cron Changes
- Removed
importData(ran every minute — ~1,440 PHP executions/day) - Removed
importBidSpirit(ran hourly — ~24 PHP executions/day) - Added
syncSafety(runs hourly at :10 — 24 PHP executions/day) - Net effect: ~62 PHP executions/hour → 1 PHP execution/hour
- WP-Cron safety hook (
auctionforge_sync_safety) — Always-active hourly event, independent of external cron - setup.sh v3 — Updated task definitions, new
migratecommand for interactive v2→v3 transition
Database
- New table:
af_sync_queue— Job queue with status, priority, source, attempts, worker PID, timing columns - New table:
af_sync_log— Real-time log entries with context, level, auction_id, job_id - DB version: 20 → 22
Constants Added
| Constant | Default | Description |
|---|---|---|
|
AUCTIONFORGE_SYNC_WORKER_TIMEOUT| 240 | Worker process timeout in seconds ||
AUCTIONFORGE_SYNC_STALE_JOB| 600 | Seconds before a processing job is considered stuck ||
AUCTIONFORGE_SYNC_HEALTH_CHECK| 86400 | Seconds without webhook before triggering full sync ||
AUCTIONFORGE_SYNC_LOG_RETENTION| 7 | Days to keep log entries ||
AUCTIONFORGE_SYNC_QUEUE_RETENTION| 30 | Days to keep completed queue jobs ||
AUCTIONFORGE_CURL_TIMEOUT| 30 | BidSpirit API cURL timeout in seconds ||
AUCTIONFORGE_PHP_BINARY| /www/server/php/83/bin/php | PHP CLI binary path for spawning workers |AJAX Handlers Added
auctionforge_sync_log_poll— Incremental log polling for live consoleauctionforge_sync_queue_status— Queue counts + recent jobs for dashboardauctionforge_sync_enqueue— Admin-triggered sync actions (full_sync, sync_auction, spawn_worker)
Fixes
- cURL timeout — BidSpiritRequest now enforces a 30-second timeout (was unlimited/0), preventing hung connections from blocking the sync pipeline.
Files Changed
- Modified:
auctionforge.php,inc/coreIncludes.php,inc/controllers/AuctionsAPI.php,inc/BidSpiritRequest.php,admin/view/sync-status.php,crontasks/setup.sh - Created:
inc/sync/SyncQueue.php,inc/sync/SyncLogger.php,inc/sync/CatalogSyncWorker.php,inc/sync/ItemUpdateWorker.php,crontasks/syncWorker.php,crontasks/syncSafety.php
---
[2.7.3.0]
Fixes
- Various stability improvements and bug fixes.
[2.7.1.2]
Fixes
- Added missing
vatAndCommission()function inloadBid()— the sales tax display on single lot pages was never being rendered because the code to callloadTemplateforvat-and-commission-templatewas missing fromapp.js.
[2.7.1.1]
Fixes
- 2 decimal places now only appear in the bid modal (Your max bid, Total Price) via
showDecimalsflag. 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.
[2.7.0.9]
Fixes
- Fixed fatal error during plugin install/upgrade:
class-stats-database.phprequire failure.
[2.7.0.0]
New Features: Advanced Lot Analytics
- Conversion Tracking, Peak Viewing Times, Pre-Sale vs Live Comparison, Category Performance, Share Analytics, Search → View Funnel, Click-Through Tracking, CSV Export, Hot Lot Badge.
- New DB table:
af_lot_shares. New columns onaf_lot_analytics. DB version bumped to 20.
[2.6.0.0]
New Feature: Lot Analytics
- Comprehensive lot view and favorite tracking system with admin dashboard.
[2.5.0.0]
New Features
- Site Statistics System — Full website analytics built into the plugin admin.
- Recently Viewed Items — Profile page tab showing last 20 viewed lots per user.
- Timed Auction Badge Visibility — Fixed a strict type-matching bug in the main
-
v3.2.9.3 Stable Apr 02, 2026Download v3.2.9.3📦 8.82 MB⚙️ WP 5.2+🔧 PHP 7.2+✓ Tested 6.4
AuctionForge Changelog
All notable changes to the AuctionForge plugin are documented in this file.
---
[3.2.9.2] — 2026-03-30
Timed Auction Archive Fix
Fixes
- Timed Auction Badge Visibility — Fixed a strict type-matching bug in the main
auction_list.phpcore file that incorrectly hid the "Timed Auction" badge overlay from valid timed/online auctions on the main upcoming/archive views. The badge now displays properly across all manual and Bidspirit-synced objects when toggled on.
Files Changed
- Modified:
templates/main/auction_list.php
---
[3.2.9.1] — 2026-03-30
Timed Auction Display Enhancements
Features
- Timed Auction Countdown Text Toggle — Added a WP-Admin setting "Change text to 'Auction will close in'" that conditionally changes the countdown label for timed/online auctions on single lot pages.
- Shortcode Text Toggle Support — Extended the new countdown text logic to the
bp_upcoming_wideshortcodes so "Live bidding starts in:" successfully transitions to "Auction will close in:" for timed auctions.
Files Changed
- Modified:
inc/controllers/Settings.php,templates/single-lot.php,templates/shortcodes/upcoming-auction-wide.php,templates/shortcodes/upcoming-auction-wide-manual.php
---
[3.2.9.0] — 2026-03-29
Billing & Invoices Polish
Fixes
- Profile Invoice ID Tracking — Prevented internal auction codes (e.g.
002orai4) from breaking into the clean hyphenated titles inside theprofile-templates.phpview. - Dynamic Payment Statuses — Replaced Bidspirit's default/cached
NOT PAIDHTML payloads by wiring thedompdfgenerator to directly respect the current$b.statusstring from the API (resolving instances where a paid invoice still printed "NOT PAID" atop the document). - Payment Instructions Conditional — Automatically hide the "Payment Instructions" block from the PDF footer when an invoice is fully paid.
- Improved Nomenclature — Changed "Invoice No:" to "Bidder No:" on document output to prevent confusion with static invoice ledger IDs.
---
[3.2.6.0] — 2026-03-28
Multi-Day Auction Lot Filtering Fix
Fixes
- Day 2+ showing lots from Day 1 in multi-day auctions — The
itemIndexcolumn inbp_meta_dataisvarchar(55), but the day-range filter inBidspiritQuery::bp_query_where()was comparing it as a string. With string comparison, lot numbers like'11','101'–'145'incorrectly fell between'1001'and'1450', causing Day 1 lots to leak into Day 2 results. Fixed by usingCAST(bpMeta.itemIndex AS UNSIGNED)for numeric comparison andintval()on the PHP-side boundary values. Letter lots (e.g.14A,1025A) are handled correctly —CASTstrips the suffix, keeping them grouped with their base lot number.
Files Changed
- Modified:
inc/controllers/BidspiritQuery.php
---
[3.2.5.9] — 2026-03-27
Catalog Page Fix
Fixes
- Duplicate preview hours on catalog pages — The
displayHoursfield was rendered twice: once via thebp_after_description_auctionhook inBidspiritViews.phpand once inline in the auction template. Removed the hook-based rendering to eliminate the duplication.
Files Changed
- Modified:
inc/controllers/BidspiritViews.php,templates/main/auction.php
---
[3.2.5] — 2026-03-19
Sync Reliability & Stuck Lot Prevention
Fixes
- CATALOG_PUBLISHED webhook now triggers catalog sync — Previously only sent push notifications without syncing lots. When the earlier AUCTION_CATALOG_UPDATED fired before the catalog was ready on BidSpirit, lots were never imported. CATALOG_PUBLISHED now calls
auctionCatalogUpdated()to trigger a full catalog sync when the catalog is actually available. - 0-lot API results now fail instead of silently succeeding — When BidSpirit API returns 0 lots (catalog not yet ready), the sync job now fails with an explicit error message, allowing the next webhook to create a fresh retry job.
- Expanded CDN allowlist in pre_http_request filter — The HTTP filter during bulk post insertion now allows all
*.bidspirit.comsubdomains and BidSpirit image CDNs (fastly.net,cloudfront.net). Previously onlybidspirit.comandwww.bidspirit.comwere allowed, blocking image downloads during sync and causing worker hangs. - InsertLotsBS timeout guard — Stage 5 (InsertLotsBS processing loop) now has a 180-second timeout and logs progress every 2 batches. Prevents indefinite hangs that previously required manual force-kill.
- fixResult() no longer marks lots as done when postId=0 — When
lotProcessing()fails to create a WP post, the staging row now keepssyncFinished=0so the lot is retried on the next sync pass, instead of being permanently marked as complete with no actual post. - lotProcessing() logs error on missing auction term — Previously returned 0 silently when
Auction::findAuctionById()failed. Now logs an explicit error that feeds intofixResult()to keep the lot retryable. - Hourly orphan detection in safety cron — New step in
syncSafety.phpdetects lot posts that exist inbp_meta_databut are missing their auction taxonomy assignment (caused by workers killed mid-batch) and auto-repairs them withwp_set_object_terms().
Files Changed
- Modified:
inc/controllers/AuctionsAPI.php,inc/sync/CatalogSyncWorker.php,inc/abs/InsertLotsAbstract.php,inc/import/InsertLotsBS.php,crontasks/syncSafety.php
---
[3.2.4] — 2026-03-18
Sync Worker Hang Fix
Fixes
- Sync workers hanging at InsertLotsBS stage — Third-party plugins (Smush Pro, SmartCrawl SEO, WPMU DEV Updates) hook into
wp_insert_post()and make blocking outbound HTTPS calls for every lot processed. With 489+ lots per auction, this caused workers to hang indefinitely on socket reads to WPMU DEV servers (32.193.94.25,32.193.93.106). AddedWP_IMPORTINGconstant at the REST worker entry point and apre_http_requestfilter inCatalogSyncWorkerthat blocks all non-essential external HTTP during the batch post-insertion phase. Loopback (127.0.0.1,localhost) and BidSpirit API calls remain allowed. - Stuck staging rows after force-kill — When workers were force-killed mid-sync, staging rows in
import_historywere left withsyncstart=1and never unblocked. Subsequent sync runs could not see these rows (filtered out byLot::getRawLots()), causing the InsertLotsBS loop to exit immediately with 0 posts processed. Combined with job deduplication (SyncQueue::enqueue()skips if aprocessingjob exists), this created a deadlock where no new sync could proceed.
Files Changed
- Modified:
auctionforge.php,inc/sync/CatalogSyncWorker.php
---
[3.2.2] — 2026-03-17
Full Sync Auction Discovery Fix
Fixes
- Full Sync finds no auctions on fresh sites — The v3
full_syncaction only queried the WordPress database for existing auction terms, but on a freshly deployed site the database has zero auctions. AddedAuctionList::init()discovery step before querying the DB, so Full Sync now fetches all auctions from the BidSpirit API and creates taxonomy terms first, then enqueues catalog sync jobs for each.
Files Changed
- Modified:
auctionforge.php
---
[3.2.0] — 2026-03-14
Webhook Pipeline Fixes, Archive Sync & Admin UI Overhaul
New Features
- Archive Sync — New "Archive Sync" button on Sync Status admin page. Enqueues catalog sync jobs for all ARCHIVED/ENDED auctions. Past auctions now appear in the auction dropdown with an optgroup separator and state label.
- Sync Tasks v3 — Replaced old v2 task cards (importData, importBidSpirit, lotBidSpiritOld) with v3 queue-based tasks. "Sync Active Auctions" and "Sync Archived Auctions" now enqueue jobs via the queue system. Maintenance tasks (Clean Draft/Trash Lots, Clean Orphaned Meta) remain as direct-execution tasks.
- How It Works guide rewritten — Complete rewrite of the admin guide for v3 architecture. Documents webhook-first flow, all 5 job types, queue system mechanics, cron setup (external + WP-Cron), configuration constants, and troubleshooting.
Fixes
- Dual-write removed — Removed legacy handlers from
auctionCatalogUpdated(),auctionDayEnded(), anditemsUpdated()webhook methods. The old handlers were racing with the v3 worker, creating orphaned staging rows inimport_historythat were never processed. All three methods now exclusively use the v3 enqueue → spawn path. - ITEMS_UPDATED webhook — Fixed
itemsUpdated()failing to enqueue jobs. TheITEMS_UPDATEDpayload hasauctionIdnested initemsByLanguage.{lang}[0].item.auctionId, not at the top level. Added extraction logic to resolve it. - ItemUpdateWorker incomplete —
ItemUpdateWorker::process()was only callingLot::bulkSave()(staging table) without runningInsertLotsBSto process staged data into WP posts andbp_meta_data. Added the InsertLotsBS processing step with autocommit restore. Item updates now flow: stage → InsertLotsBS → WP post + meta → cache clear. - Worker spawn reliability — Changed
SyncQueue::spawnWorker()from non-blocking HTTPS to blocking HTTP loopback (http://127.0.0.1with explicitHostheader, 2s timeout). Fixes nginx 403/404 errors when HTTPS loopback hits the default vhost instead of the site's vhost. - API token constant — Plugin expects
AUCTIONFORGE_API_TOKENinwp-config.php(renamed fromUCO_API_TOKENduring the plugin rename). Documented in readme.
Database
- DB version: 22 → 23
Files Changed
- Modified:
inc/controllers/AuctionsAPI.php,inc/sync/ItemUpdateWorker.php,inc/sync/SyncQueue.php,auctionforge.php,admin/view/sync-status.php,readme.txt
---
[3.0.0] — 2025-03-14
New Feature: Webhook-First Sync Architecture (Sync v3)
Overview: Complete redesign of the BidSpirit data synchronisation pipeline. Replaces the old two-phase polling system (importBidSpirit every hour + importData every minute) with a webhook-driven job queue that processes data in near real-time.
Architecture
- 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: webhook → queue → background worker → WordPress posts. - Dual-write mode — During transition, webhooks enqueue jobs AND still run the legacy handlers. Once verified, legacy handlers can be removed cleanly.
- Job deduplication — Prevents duplicate work by checking for existing pending/processing jobs with the same auction_id + job_type.
New Components
- Job Queue System (
inc/sync/SyncQueue.php) — Priority-based FIFO queue with atomic job claiming, status tracking (pending/processing/completed/failed/skipped), worker PID tracking, and automatic stuck job recovery. - Sync Logger (
inc/sync/SyncLogger.php) — Real-time log table for admin console polling with level filtering (info/success/warning/error) and incremental cursor-based retrieval. - Catalog Sync Worker (
inc/sync/CatalogSyncWorker.php) — Processes catalog_sync, full_sync, and day_ended jobs by reusing existingLotList::singleRun()logic. - Item Update Worker (
inc/sync/ItemUpdateWorker.php) — Processes individual item_update jobs with the same logic as the webhookitemsUpdatedhandler. - Background Worker (
crontasks/syncWorker.php) — Async CLI process spawned by webhooks viaexec()or by the safety cron. Claims and processes queued jobs with a configurable timeout (default 240s). - Safety Net (
crontasks/syncSafety.php) — Hourly cron that resets stuck jobs (>10min), spawns workers for pending jobs, runs a 24-hour health check (auto-enqueues full sync if no webhooks received), and purges old data.
Admin UI
- Queue Status Dashboard — New card on Sync Status page showing pending/processing/completed/failed/skipped counts, recent jobs table with real-time refresh, worker status badge, and action buttons:
- Full Sync — Enqueues catalog sync for all active auctions
- Sync Selected — Enqueue a single auction from dropdown
- Spawn Worker — Manually trigger a background worker process
- Live Console — Dark-themed terminal console on the Sync Status page. Polls
af_sync_logevery 1.5s showing timestamped, color-coded log entries from webhooks, workers, queue operations, and the safety cron. Supports pause, clear, and auto-scroll.
Cron Changes
- Removed
importData(ran every minute — ~1,440 PHP executions/day) - Removed
importBidSpirit(ran hourly — ~24 PHP executions/day) - Added
syncSafety(runs hourly at :10 — 24 PHP executions/day) - Net effect: ~62 PHP executions/hour → 1 PHP execution/hour
- WP-Cron safety hook (
auctionforge_sync_safety) — Always-active hourly event, independent of external cron - setup.sh v3 — Updated task definitions, new
migratecommand for interactive v2→v3 transition
Database
- New table:
af_sync_queue— Job queue with status, priority, source, attempts, worker PID, timing columns - New table:
af_sync_log— Real-time log entries with context, level, auction_id, job_id - DB version: 20 → 22
Constants Added
| Constant | Default | Description |
|---|---|---|
|
AUCTIONFORGE_SYNC_WORKER_TIMEOUT| 240 | Worker process timeout in seconds ||
AUCTIONFORGE_SYNC_STALE_JOB| 600 | Seconds before a processing job is considered stuck ||
AUCTIONFORGE_SYNC_HEALTH_CHECK| 86400 | Seconds without webhook before triggering full sync ||
AUCTIONFORGE_SYNC_LOG_RETENTION| 7 | Days to keep log entries ||
AUCTIONFORGE_SYNC_QUEUE_RETENTION| 30 | Days to keep completed queue jobs ||
AUCTIONFORGE_CURL_TIMEOUT| 30 | BidSpirit API cURL timeout in seconds ||
AUCTIONFORGE_PHP_BINARY| /www/server/php/83/bin/php | PHP CLI binary path for spawning workers |AJAX Handlers Added
auctionforge_sync_log_poll— Incremental log polling for live consoleauctionforge_sync_queue_status— Queue counts + recent jobs for dashboardauctionforge_sync_enqueue— Admin-triggered sync actions (full_sync, sync_auction, spawn_worker)
Fixes
- cURL timeout — BidSpiritRequest now enforces a 30-second timeout (was unlimited/0), preventing hung connections from blocking the sync pipeline.
Files Changed
- Modified:
auctionforge.php,inc/coreIncludes.php,inc/controllers/AuctionsAPI.php,inc/BidSpiritRequest.php,admin/view/sync-status.php,crontasks/setup.sh - Created:
inc/sync/SyncQueue.php,inc/sync/SyncLogger.php,inc/sync/CatalogSyncWorker.php,inc/sync/ItemUpdateWorker.php,crontasks/syncWorker.php,crontasks/syncSafety.php
---
[2.7.3.0]
Fixes
- Various stability improvements and bug fixes.
[2.7.1.2]
Fixes
- Added missing
vatAndCommission()function inloadBid()— the sales tax display on single lot pages was never being rendered because the code to callloadTemplateforvat-and-commission-templatewas missing fromapp.js.
[2.7.1.1]
Fixes
- 2 decimal places now only appear in the bid modal (Your max bid, Total Price) via
showDecimalsflag. 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.
[2.7.0.9]
Fixes
- Fixed fatal error during plugin install/upgrade:
class-stats-database.phprequire failure.
[2.7.0.0]
New Features: Advanced Lot Analytics
- Conversion Tracking, Peak Viewing Times, Pre-Sale vs Live Comparison, Category Performance, Share Analytics, Search → View Funnel, Click-Through Tracking, CSV Export, Hot Lot Badge.
- New DB table:
af_lot_shares. New columns onaf_lot_analytics. DB version bumped to 20.
[2.6.0.0]
New Feature: Lot Analytics
- Comprehensive lot view and favorite tracking system with admin dashboard.
[2.5.0.0]
New Features
- Site Statistics System — Full website analytics built into the plugin admin.
- Recently Viewed Items — Profile page tab showing last 20 viewed lots per user.
- Timed Auction Badge Visibility — Fixed a strict type-matching bug in the main
-
v3.2.9.2 Stable Mar 30, 2026Download v3.2.9.2📦 8.82 MB⚙️ WP 5.2+🔧 PHP 7.2+✓ Tested 6.4
[3.2.9.2] — 2026-03-30
Timed Auction Archive Fix
Fixes
- Timed Auction Badge Visibility — Fixed a strict type-matching bug in the main
auction_list.phpcore file that incorrectly hid the "Timed Auction" badge overlay from valid timed/online auctions on the main upcoming/archive views. The badge now displays properly across all manual and Bidspirit-synced objects when toggled on.
Files Changed
- Modified:
templates/main/auction_list.php
---
- Timed Auction Badge Visibility — Fixed a strict type-matching bug in the main
-
v3.2.9.0 Stable Mar 30, 2026Download v3.2.9.0📦 8.82 MB⚙️ WP 5.2+🔧 PHP 7.2+✓ Tested 6.4
[3.2.9.0] — 2026-03-29
Billing & Invoices Polish
Fixes
- Profile Invoice ID Tracking — Prevented internal auction codes (e.g.
002orai4) from breaking into the clean hyphenated titles inside theprofile-templates.phpview. - Dynamic Payment Statuses — Replaced Bidspirit's default/cached
NOT PAIDHTML payloads by wiring thedompdfgenerator to directly respect the current$b.statusstring from the API (resolving instances where a paid invoice still printed "NOT PAID" atop the document). - Payment Instructions Conditional — Automatically hide the "Payment Instructions" block from the PDF footer when an invoice is fully paid.
- Improved Nomenclature — Changed "Invoice No:" to "Bidder No:" on document output to prevent confusion with static invoice ledger IDs.
---
- Profile Invoice ID Tracking — Prevented internal auction codes (e.g.
-
v3.2.6.0 Stable Mar 28, 2026Download v3.2.6.0📦 4.85 MB⚙️ WP 5.2+🔧 PHP 7.2+✓ Tested 6.4
[3.2.6.0] — 2026-03-28
Multi-Day Auction Lot Filtering Fix
Fixes
- Day 2+ showing lots from Day 1 in multi-day auctions — The
itemIndexcolumn inbp_meta_dataisvarchar(55), but the day-range filter inBidspiritQuery::bp_query_where()was comparing it as a string. With string comparison, lot numbers like'11','101'–'145'incorrectly fell between'1001'and'1450', causing Day 1 lots to leak into Day 2 results. Fixed by usingCAST(bpMeta.itemIndex AS UNSIGNED)for numeric comparison andintval()on the PHP-side boundary values. Letter lots (e.g.14A,1025A) are handled correctly —CASTstrips the suffix, keeping them grouped with their base lot number.
Files Changed
- Modified:
inc/controllers/BidspiritQuery.php
---
- Day 2+ showing lots from Day 1 in multi-day auctions — The
-
v3.2.5.9 Stable Mar 27, 2026Download v3.2.5.9📦 4.85 MB⚙️ WP 5.2+🔧 PHP 7.2+✓ Tested 6.4
[3.2.5.9] — 2026-03-27
Catalog Page Fix
Fixes
- Duplicate preview hours on catalog pages — The
displayHoursfield was rendered twice: once via thebp_after_description_auctionhook inBidspiritViews.phpand once inline in the auction template. Removed the hook-based rendering to eliminate the duplication.
Files Changed
- Modified:
inc/controllers/BidspiritViews.php,templates/main/auction.php
---
- Duplicate preview hours on catalog pages — The
-
v3.2.5.8 Stable Mar 26, 2026Download v3.2.5.8📦 4.85 MB⚙️ WP 5.2+🔧 PHP 7.2+✓ Tested 6.4
AuctionForge Changelog
All notable changes to the AuctionForge plugin are documented in this file.
---
[3.2.5] — 2026-03-19
Sync Reliability & Stuck Lot Prevention
Fixes
- CATALOG_PUBLISHED webhook now triggers catalog sync — Previously only sent push notifications without syncing lots. When the earlier AUCTION_CATALOG_UPDATED fired before the catalog was ready on BidSpirit, lots were never imported. CATALOG_PUBLISHED now calls
auctionCatalogUpdated()to trigger a full catalog sync when the catalog is actually available. - 0-lot API results now fail instead of silently succeeding — When BidSpirit API returns 0 lots (catalog not yet ready), the sync job now fails with an explicit error message, allowing the next webhook to create a fresh retry job.
- Expanded CDN allowlist in pre_http_request filter — The HTTP filter during bulk post insertion now allows all
*.bidspirit.comsubdomains and BidSpirit image CDNs (fastly.net,cloudfront.net). Previously onlybidspirit.comandwww.bidspirit.comwere allowed, blocking image downloads during sync and causing worker hangs. - InsertLotsBS timeout guard — Stage 5 (InsertLotsBS processing loop) now has a 180-second timeout and logs progress every 2 batches. Prevents indefinite hangs that previously required manual force-kill.
- fixResult() no longer marks lots as done when postId=0 — When
lotProcessing()fails to create a WP post, the staging row now keepssyncFinished=0so the lot is retried on the next sync pass, instead of being permanently marked as complete with no actual post. - lotProcessing() logs error on missing auction term — Previously returned 0 silently when
Auction::findAuctionById()failed. Now logs an explicit error that feeds intofixResult()to keep the lot retryable. - Hourly orphan detection in safety cron — New step in
syncSafety.phpdetects lot posts that exist inbp_meta_databut are missing their auction taxonomy assignment (caused by workers killed mid-batch) and auto-repairs them withwp_set_object_terms().
Files Changed
- Modified:
inc/controllers/AuctionsAPI.php,inc/sync/CatalogSyncWorker.php,inc/abs/InsertLotsAbstract.php,inc/import/InsertLotsBS.php,crontasks/syncSafety.php
---
[3.2.4] — 2026-03-18
Sync Worker Hang Fix
Fixes
- Sync workers hanging at InsertLotsBS stage — Third-party plugins (Smush Pro, SmartCrawl SEO, WPMU DEV Updates) hook into
wp_insert_post()and make blocking outbound HTTPS calls for every lot processed. With 489+ lots per auction, this caused workers to hang indefinitely on socket reads to WPMU DEV servers (32.193.94.25,32.193.93.106). AddedWP_IMPORTINGconstant at the REST worker entry point and apre_http_requestfilter inCatalogSyncWorkerthat blocks all non-essential external HTTP during the batch post-insertion phase. Loopback (127.0.0.1,localhost) and BidSpirit API calls remain allowed. - Stuck staging rows after force-kill — When workers were force-killed mid-sync, staging rows in
import_historywere left withsyncstart=1and never unblocked. Subsequent sync runs could not see these rows (filtered out byLot::getRawLots()), causing the InsertLotsBS loop to exit immediately with 0 posts processed. Combined with job deduplication (SyncQueue::enqueue()skips if aprocessingjob exists), this created a deadlock where no new sync could proceed.
Files Changed
- Modified:
auctionforge.php,inc/sync/CatalogSyncWorker.php
---
[3.2.2] — 2026-03-17
Full Sync Auction Discovery Fix
Fixes
- Full Sync finds no auctions on fresh sites — The v3
full_syncaction only queried the WordPress database for existing auction terms, but on a freshly deployed site the database has zero auctions. AddedAuctionList::init()discovery step before querying the DB, so Full Sync now fetches all auctions from the BidSpirit API and creates taxonomy terms first, then enqueues catalog sync jobs for each.
Files Changed
- Modified:
auctionforge.php
---
[3.2.0] — 2026-03-14
Webhook Pipeline Fixes, Archive Sync & Admin UI Overhaul
New Features
- Archive Sync — New "Archive Sync" button on Sync Status admin page. Enqueues catalog sync jobs for all ARCHIVED/ENDED auctions. Past auctions now appear in the auction dropdown with an optgroup separator and state label.
- Sync Tasks v3 — Replaced old v2 task cards (importData, importBidSpirit, lotBidSpiritOld) with v3 queue-based tasks. "Sync Active Auctions" and "Sync Archived Auctions" now enqueue jobs via the queue system. Maintenance tasks (Clean Draft/Trash Lots, Clean Orphaned Meta) remain as direct-execution tasks.
- How It Works guide rewritten — Complete rewrite of the admin guide for v3 architecture. Documents webhook-first flow, all 5 job types, queue system mechanics, cron setup (external + WP-Cron), configuration constants, and troubleshooting.
Fixes
- Dual-write removed — Removed legacy handlers from
auctionCatalogUpdated(),auctionDayEnded(), anditemsUpdated()webhook methods. The old handlers were racing with the v3 worker, creating orphaned staging rows inimport_historythat were never processed. All three methods now exclusively use the v3 enqueue → spawn path. - ITEMS_UPDATED webhook — Fixed
itemsUpdated()failing to enqueue jobs. TheITEMS_UPDATEDpayload hasauctionIdnested initemsByLanguage.{lang}[0].item.auctionId, not at the top level. Added extraction logic to resolve it. - ItemUpdateWorker incomplete —
ItemUpdateWorker::process()was only callingLot::bulkSave()(staging table) without runningInsertLotsBSto process staged data into WP posts andbp_meta_data. Added the InsertLotsBS processing step with autocommit restore. Item updates now flow: stage → InsertLotsBS → WP post + meta → cache clear. - Worker spawn reliability — Changed
SyncQueue::spawnWorker()from non-blocking HTTPS to blocking HTTP loopback (http://127.0.0.1with explicitHostheader, 2s timeout). Fixes nginx 403/404 errors when HTTPS loopback hits the default vhost instead of the site's vhost. - API token constant — Plugin expects
AUCTIONFORGE_API_TOKENinwp-config.php(renamed fromUCO_API_TOKENduring the plugin rename). Documented in readme.
Database
- DB version: 22 → 23
Files Changed
- Modified:
inc/controllers/AuctionsAPI.php,inc/sync/ItemUpdateWorker.php,inc/sync/SyncQueue.php,auctionforge.php,admin/view/sync-status.php,readme.txt
---
[3.0.0] — 2025-03-14
New Feature: Webhook-First Sync Architecture (Sync v3)
Overview: Complete redesign of the BidSpirit data synchronisation pipeline. Replaces the old two-phase polling system (importBidSpirit every hour + importData every minute) with a webhook-driven job queue that processes data in near real-time.
Architecture
- 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: webhook → queue → background worker → WordPress posts. - Dual-write mode — During transition, webhooks enqueue jobs AND still run the legacy handlers. Once verified, legacy handlers can be removed cleanly.
- Job deduplication — Prevents duplicate work by checking for existing pending/processing jobs with the same auction_id + job_type.
New Components
- Job Queue System (
inc/sync/SyncQueue.php) — Priority-based FIFO queue with atomic job claiming, status tracking (pending/processing/completed/failed/skipped), worker PID tracking, and automatic stuck job recovery. - Sync Logger (
inc/sync/SyncLogger.php) — Real-time log table for admin console polling with level filtering (info/success/warning/error) and incremental cursor-based retrieval. - Catalog Sync Worker (
inc/sync/CatalogSyncWorker.php) — Processes catalog_sync, full_sync, and day_ended jobs by reusing existingLotList::singleRun()logic. - Item Update Worker (
inc/sync/ItemUpdateWorker.php) — Processes individual item_update jobs with the same logic as the webhookitemsUpdatedhandler. - Background Worker (
crontasks/syncWorker.php) — Async CLI process spawned by webhooks viaexec()or by the safety cron. Claims and processes queued jobs with a configurable timeout (default 240s). - Safety Net (
crontasks/syncSafety.php) — Hourly cron that resets stuck jobs (>10min), spawns workers for pending jobs, runs a 24-hour health check (auto-enqueues full sync if no webhooks received), and purges old data.
Admin UI
- Queue Status Dashboard — New card on Sync Status page showing pending/processing/completed/failed/skipped counts, recent jobs table with real-time refresh, worker status badge, and action buttons:
- Full Sync — Enqueues catalog sync for all active auctions
- Sync Selected — Enqueue a single auction from dropdown
- Spawn Worker — Manually trigger a background worker process
- Live Console — Dark-themed terminal console on the Sync Status page. Polls
af_sync_logevery 1.5s showing timestamped, color-coded log entries from webhooks, workers, queue operations, and the safety cron. Supports pause, clear, and auto-scroll.
Cron Changes
- Removed
importData(ran every minute — ~1,440 PHP executions/day) - Removed
importBidSpirit(ran hourly — ~24 PHP executions/day) - Added
syncSafety(runs hourly at :10 — 24 PHP executions/day) - Net effect: ~62 PHP executions/hour → 1 PHP execution/hour
- WP-Cron safety hook (
auctionforge_sync_safety) — Always-active hourly event, independent of external cron - setup.sh v3 — Updated task definitions, new
migratecommand for interactive v2→v3 transition
Database
- New table:
af_sync_queue— Job queue with status, priority, source, attempts, worker PID, timing columns - New table:
af_sync_log— Real-time log entries with context, level, auction_id, job_id - DB version: 20 → 22
Constants Added
| Constant | Default | Description |
|---|---|---|
|
AUCTIONFORGE_SYNC_WORKER_TIMEOUT| 240 | Worker process timeout in seconds ||
AUCTIONFORGE_SYNC_STALE_JOB| 600 | Seconds before a processing job is considered stuck ||
AUCTIONFORGE_SYNC_HEALTH_CHECK| 86400 | Seconds without webhook before triggering full sync ||
AUCTIONFORGE_SYNC_LOG_RETENTION| 7 | Days to keep log entries ||
AUCTIONFORGE_SYNC_QUEUE_RETENTION| 30 | Days to keep completed queue jobs ||
AUCTIONFORGE_CURL_TIMEOUT| 30 | BidSpirit API cURL timeout in seconds ||
AUCTIONFORGE_PHP_BINARY| /www/server/php/83/bin/php | PHP CLI binary path for spawning workers |AJAX Handlers Added
auctionforge_sync_log_poll— Incremental log polling for live consoleauctionforge_sync_queue_status— Queue counts + recent jobs for dashboardauctionforge_sync_enqueue— Admin-triggered sync actions (full_sync, sync_auction, spawn_worker)
Fixes
- cURL timeout — BidSpiritRequest now enforces a 30-second timeout (was unlimited/0), preventing hung connections from blocking the sync pipeline.
Files Changed
- Modified:
auctionforge.php,inc/coreIncludes.php,inc/controllers/AuctionsAPI.php,inc/BidSpiritRequest.php,admin/view/sync-status.php,crontasks/setup.sh - Created:
inc/sync/SyncQueue.php,inc/sync/SyncLogger.php,inc/sync/CatalogSyncWorker.php,inc/sync/ItemUpdateWorker.php,crontasks/syncWorker.php,crontasks/syncSafety.php
---
[2.7.3.0]
Fixes
- Various stability improvements and bug fixes.
[2.7.1.2]
Fixes
- Added missing
vatAndCommission()function inloadBid()— the sales tax display on single lot pages was never being rendered because the code to callloadTemplateforvat-and-commission-templatewas missing fromapp.js.
[2.7.1.1]
Fixes
- 2 decimal places now only appear in the bid modal (Your max bid, Total Price) via
showDecimalsflag. 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.
[2.7.0.9]
Fixes
- Fixed fatal error during plugin install/upgrade:
class-stats-database.phprequire failure.
[2.7.0.0]
New Features: Advanced Lot Analytics
- Conversion Tracking, Peak Viewing Times, Pre-Sale vs Live Comparison, Category Performance, Share Analytics, Search → View Funnel, Click-Through Tracking, CSV Export, Hot Lot Badge.
- New DB table:
af_lot_shares. New columns onaf_lot_analytics. DB version bumped to 20.
[2.6.0.0]
New Feature: Lot Analytics
- Comprehensive lot view and favorite tracking system with admin dashboard.
[2.5.0.0]
New Features
- Site Statistics System — Full website analytics built into the plugin admin.
- Recently Viewed Items — Profile page tab showing last 20 viewed lots per user.
- CATALOG_PUBLISHED webhook now triggers catalog sync — Previously only sent push notifications without syncing lots. When the earlier AUCTION_CATALOG_UPDATED fired before the catalog was ready on BidSpirit, lots were never imported. CATALOG_PUBLISHED now calls
-
v3.2.5.7 Stable Mar 24, 2026Download v3.2.5.7📦 4.85 MB⚙️ WP 5.2+🔧 PHP 7.2+✓ Tested 6.4
AuctionForge Changelog
All notable changes to the AuctionForge plugin are documented in this file.
---
[3.2.5] — 2026-03-19
Sync Reliability & Stuck Lot Prevention
Fixes
- CATALOG_PUBLISHED webhook now triggers catalog sync — Previously only sent push notifications without syncing lots. When the earlier AUCTION_CATALOG_UPDATED fired before the catalog was ready on BidSpirit, lots were never imported. CATALOG_PUBLISHED now calls
auctionCatalogUpdated()to trigger a full catalog sync when the catalog is actually available. - 0-lot API results now fail instead of silently succeeding — When BidSpirit API returns 0 lots (catalog not yet ready), the sync job now fails with an explicit error message, allowing the next webhook to create a fresh retry job.
- Expanded CDN allowlist in pre_http_request filter — The HTTP filter during bulk post insertion now allows all
*.bidspirit.comsubdomains and BidSpirit image CDNs (fastly.net,cloudfront.net). Previously onlybidspirit.comandwww.bidspirit.comwere allowed, blocking image downloads during sync and causing worker hangs. - InsertLotsBS timeout guard — Stage 5 (InsertLotsBS processing loop) now has a 180-second timeout and logs progress every 2 batches. Prevents indefinite hangs that previously required manual force-kill.
- fixResult() no longer marks lots as done when postId=0 — When
lotProcessing()fails to create a WP post, the staging row now keepssyncFinished=0so the lot is retried on the next sync pass, instead of being permanently marked as complete with no actual post. - lotProcessing() logs error on missing auction term — Previously returned 0 silently when
Auction::findAuctionById()failed. Now logs an explicit error that feeds intofixResult()to keep the lot retryable. - Hourly orphan detection in safety cron — New step in
syncSafety.phpdetects lot posts that exist inbp_meta_databut are missing their auction taxonomy assignment (caused by workers killed mid-batch) and auto-repairs them withwp_set_object_terms().
Files Changed
- Modified:
inc/controllers/AuctionsAPI.php,inc/sync/CatalogSyncWorker.php,inc/abs/InsertLotsAbstract.php,inc/import/InsertLotsBS.php,crontasks/syncSafety.php
---
[3.2.4] — 2026-03-18
Sync Worker Hang Fix
Fixes
- Sync workers hanging at InsertLotsBS stage — Third-party plugins (Smush Pro, SmartCrawl SEO, WPMU DEV Updates) hook into
wp_insert_post()and make blocking outbound HTTPS calls for every lot processed. With 489+ lots per auction, this caused workers to hang indefinitely on socket reads to WPMU DEV servers (32.193.94.25,32.193.93.106). AddedWP_IMPORTINGconstant at the REST worker entry point and apre_http_requestfilter inCatalogSyncWorkerthat blocks all non-essential external HTTP during the batch post-insertion phase. Loopback (127.0.0.1,localhost) and BidSpirit API calls remain allowed. - Stuck staging rows after force-kill — When workers were force-killed mid-sync, staging rows in
import_historywere left withsyncstart=1and never unblocked. Subsequent sync runs could not see these rows (filtered out byLot::getRawLots()), causing the InsertLotsBS loop to exit immediately with 0 posts processed. Combined with job deduplication (SyncQueue::enqueue()skips if aprocessingjob exists), this created a deadlock where no new sync could proceed.
Files Changed
- Modified:
auctionforge.php,inc/sync/CatalogSyncWorker.php
---
[3.2.2] — 2026-03-17
Full Sync Auction Discovery Fix
Fixes
- Full Sync finds no auctions on fresh sites — The v3
full_syncaction only queried the WordPress database for existing auction terms, but on a freshly deployed site the database has zero auctions. AddedAuctionList::init()discovery step before querying the DB, so Full Sync now fetches all auctions from the BidSpirit API and creates taxonomy terms first, then enqueues catalog sync jobs for each.
Files Changed
- Modified:
auctionforge.php
---
[3.2.0] — 2026-03-14
Webhook Pipeline Fixes, Archive Sync & Admin UI Overhaul
New Features
- Archive Sync — New "Archive Sync" button on Sync Status admin page. Enqueues catalog sync jobs for all ARCHIVED/ENDED auctions. Past auctions now appear in the auction dropdown with an optgroup separator and state label.
- Sync Tasks v3 — Replaced old v2 task cards (importData, importBidSpirit, lotBidSpiritOld) with v3 queue-based tasks. "Sync Active Auctions" and "Sync Archived Auctions" now enqueue jobs via the queue system. Maintenance tasks (Clean Draft/Trash Lots, Clean Orphaned Meta) remain as direct-execution tasks.
- How It Works guide rewritten — Complete rewrite of the admin guide for v3 architecture. Documents webhook-first flow, all 5 job types, queue system mechanics, cron setup (external + WP-Cron), configuration constants, and troubleshooting.
Fixes
- Dual-write removed — Removed legacy handlers from
auctionCatalogUpdated(),auctionDayEnded(), anditemsUpdated()webhook methods. The old handlers were racing with the v3 worker, creating orphaned staging rows inimport_historythat were never processed. All three methods now exclusively use the v3 enqueue → spawn path. - ITEMS_UPDATED webhook — Fixed
itemsUpdated()failing to enqueue jobs. TheITEMS_UPDATEDpayload hasauctionIdnested initemsByLanguage.{lang}[0].item.auctionId, not at the top level. Added extraction logic to resolve it. - ItemUpdateWorker incomplete —
ItemUpdateWorker::process()was only callingLot::bulkSave()(staging table) without runningInsertLotsBSto process staged data into WP posts andbp_meta_data. Added the InsertLotsBS processing step with autocommit restore. Item updates now flow: stage → InsertLotsBS → WP post + meta → cache clear. - Worker spawn reliability — Changed
SyncQueue::spawnWorker()from non-blocking HTTPS to blocking HTTP loopback (http://127.0.0.1with explicitHostheader, 2s timeout). Fixes nginx 403/404 errors when HTTPS loopback hits the default vhost instead of the site's vhost. - API token constant — Plugin expects
AUCTIONFORGE_API_TOKENinwp-config.php(renamed fromUCO_API_TOKENduring the plugin rename). Documented in readme.
Database
- DB version: 22 → 23
Files Changed
- Modified:
inc/controllers/AuctionsAPI.php,inc/sync/ItemUpdateWorker.php,inc/sync/SyncQueue.php,auctionforge.php,admin/view/sync-status.php,readme.txt
---
[3.0.0] — 2025-03-14
New Feature: Webhook-First Sync Architecture (Sync v3)
Overview: Complete redesign of the BidSpirit data synchronisation pipeline. Replaces the old two-phase polling system (importBidSpirit every hour + importData every minute) with a webhook-driven job queue that processes data in near real-time.
Architecture
- 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: webhook → queue → background worker → WordPress posts. - Dual-write mode — During transition, webhooks enqueue jobs AND still run the legacy handlers. Once verified, legacy handlers can be removed cleanly.
- Job deduplication — Prevents duplicate work by checking for existing pending/processing jobs with the same auction_id + job_type.
New Components
- Job Queue System (
inc/sync/SyncQueue.php) — Priority-based FIFO queue with atomic job claiming, status tracking (pending/processing/completed/failed/skipped), worker PID tracking, and automatic stuck job recovery. - Sync Logger (
inc/sync/SyncLogger.php) — Real-time log table for admin console polling with level filtering (info/success/warning/error) and incremental cursor-based retrieval. - Catalog Sync Worker (
inc/sync/CatalogSyncWorker.php) — Processes catalog_sync, full_sync, and day_ended jobs by reusing existingLotList::singleRun()logic. - Item Update Worker (
inc/sync/ItemUpdateWorker.php) — Processes individual item_update jobs with the same logic as the webhookitemsUpdatedhandler. - Background Worker (
crontasks/syncWorker.php) — Async CLI process spawned by webhooks viaexec()or by the safety cron. Claims and processes queued jobs with a configurable timeout (default 240s). - Safety Net (
crontasks/syncSafety.php) — Hourly cron that resets stuck jobs (>10min), spawns workers for pending jobs, runs a 24-hour health check (auto-enqueues full sync if no webhooks received), and purges old data.
Admin UI
- Queue Status Dashboard — New card on Sync Status page showing pending/processing/completed/failed/skipped counts, recent jobs table with real-time refresh, worker status badge, and action buttons:
- Full Sync — Enqueues catalog sync for all active auctions
- Sync Selected — Enqueue a single auction from dropdown
- Spawn Worker — Manually trigger a background worker process
- Live Console — Dark-themed terminal console on the Sync Status page. Polls
af_sync_logevery 1.5s showing timestamped, color-coded log entries from webhooks, workers, queue operations, and the safety cron. Supports pause, clear, and auto-scroll.
Cron Changes
- Removed
importData(ran every minute — ~1,440 PHP executions/day) - Removed
importBidSpirit(ran hourly — ~24 PHP executions/day) - Added
syncSafety(runs hourly at :10 — 24 PHP executions/day) - Net effect: ~62 PHP executions/hour → 1 PHP execution/hour
- WP-Cron safety hook (
auctionforge_sync_safety) — Always-active hourly event, independent of external cron - setup.sh v3 — Updated task definitions, new
migratecommand for interactive v2→v3 transition
Database
- New table:
af_sync_queue— Job queue with status, priority, source, attempts, worker PID, timing columns - New table:
af_sync_log— Real-time log entries with context, level, auction_id, job_id - DB version: 20 → 22
Constants Added
| Constant | Default | Description |
|---|---|---|
|
AUCTIONFORGE_SYNC_WORKER_TIMEOUT| 240 | Worker process timeout in seconds ||
AUCTIONFORGE_SYNC_STALE_JOB| 600 | Seconds before a processing job is considered stuck ||
AUCTIONFORGE_SYNC_HEALTH_CHECK| 86400 | Seconds without webhook before triggering full sync ||
AUCTIONFORGE_SYNC_LOG_RETENTION| 7 | Days to keep log entries ||
AUCTIONFORGE_SYNC_QUEUE_RETENTION| 30 | Days to keep completed queue jobs ||
AUCTIONFORGE_CURL_TIMEOUT| 30 | BidSpirit API cURL timeout in seconds ||
AUCTIONFORGE_PHP_BINARY| /www/server/php/83/bin/php | PHP CLI binary path for spawning workers |AJAX Handlers Added
auctionforge_sync_log_poll— Incremental log polling for live consoleauctionforge_sync_queue_status— Queue counts + recent jobs for dashboardauctionforge_sync_enqueue— Admin-triggered sync actions (full_sync, sync_auction, spawn_worker)
Fixes
- cURL timeout — BidSpiritRequest now enforces a 30-second timeout (was unlimited/0), preventing hung connections from blocking the sync pipeline.
Files Changed
- Modified:
auctionforge.php,inc/coreIncludes.php,inc/controllers/AuctionsAPI.php,inc/BidSpiritRequest.php,admin/view/sync-status.php,crontasks/setup.sh - Created:
inc/sync/SyncQueue.php,inc/sync/SyncLogger.php,inc/sync/CatalogSyncWorker.php,inc/sync/ItemUpdateWorker.php,crontasks/syncWorker.php,crontasks/syncSafety.php
---
[2.7.3.0]
Fixes
- Various stability improvements and bug fixes.
[2.7.1.2]
Fixes
- Added missing
vatAndCommission()function inloadBid()— the sales tax display on single lot pages was never being rendered because the code to callloadTemplateforvat-and-commission-templatewas missing fromapp.js.
[2.7.1.1]
Fixes
- 2 decimal places now only appear in the bid modal (Your max bid, Total Price) via
showDecimalsflag. 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.
[2.7.0.9]
Fixes
- Fixed fatal error during plugin install/upgrade:
class-stats-database.phprequire failure.
[2.7.0.0]
New Features: Advanced Lot Analytics
- Conversion Tracking, Peak Viewing Times, Pre-Sale vs Live Comparison, Category Performance, Share Analytics, Search → View Funnel, Click-Through Tracking, CSV Export, Hot Lot Badge.
- New DB table:
af_lot_shares. New columns onaf_lot_analytics. DB version bumped to 20.
[2.6.0.0]
New Feature: Lot Analytics
- Comprehensive lot view and favorite tracking system with admin dashboard.
[2.5.0.0]
New Features
- Site Statistics System — Full website analytics built into the plugin admin.
- Recently Viewed Items — Profile page tab showing last 20 viewed lots per user.
- CATALOG_PUBLISHED webhook now triggers catalog sync — Previously only sent push notifications without syncing lots. When the earlier AUCTION_CATALOG_UPDATED fired before the catalog was ready on BidSpirit, lots were never imported. CATALOG_PUBLISHED now calls
-
v3.2.5.6 Stable Mar 24, 2026Download v3.2.5.6📦 4.85 MB⚙️ WP 5.2+🔧 PHP 7.2+✓ Tested 6.4
AuctionForge Changelog
All notable changes to the AuctionForge plugin are documented in this file.
---
[3.2.5] — 2026-03-19
Sync Reliability & Stuck Lot Prevention
Fixes
- CATALOG_PUBLISHED webhook now triggers catalog sync — Previously only sent push notifications without syncing lots. When the earlier AUCTION_CATALOG_UPDATED fired before the catalog was ready on BidSpirit, lots were never imported. CATALOG_PUBLISHED now calls
auctionCatalogUpdated()to trigger a full catalog sync when the catalog is actually available. - 0-lot API results now fail instead of silently succeeding — When BidSpirit API returns 0 lots (catalog not yet ready), the sync job now fails with an explicit error message, allowing the next webhook to create a fresh retry job.
- Expanded CDN allowlist in pre_http_request filter — The HTTP filter during bulk post insertion now allows all
*.bidspirit.comsubdomains and BidSpirit image CDNs (fastly.net,cloudfront.net). Previously onlybidspirit.comandwww.bidspirit.comwere allowed, blocking image downloads during sync and causing worker hangs. - InsertLotsBS timeout guard — Stage 5 (InsertLotsBS processing loop) now has a 180-second timeout and logs progress every 2 batches. Prevents indefinite hangs that previously required manual force-kill.
- fixResult() no longer marks lots as done when postId=0 — When
lotProcessing()fails to create a WP post, the staging row now keepssyncFinished=0so the lot is retried on the next sync pass, instead of being permanently marked as complete with no actual post. - lotProcessing() logs error on missing auction term — Previously returned 0 silently when
Auction::findAuctionById()failed. Now logs an explicit error that feeds intofixResult()to keep the lot retryable. - Hourly orphan detection in safety cron — New step in
syncSafety.phpdetects lot posts that exist inbp_meta_databut are missing their auction taxonomy assignment (caused by workers killed mid-batch) and auto-repairs them withwp_set_object_terms().
Files Changed
- Modified:
inc/controllers/AuctionsAPI.php,inc/sync/CatalogSyncWorker.php,inc/abs/InsertLotsAbstract.php,inc/import/InsertLotsBS.php,crontasks/syncSafety.php
---
[3.2.4] — 2026-03-18
Sync Worker Hang Fix
Fixes
- Sync workers hanging at InsertLotsBS stage — Third-party plugins (Smush Pro, SmartCrawl SEO, WPMU DEV Updates) hook into
wp_insert_post()and make blocking outbound HTTPS calls for every lot processed. With 489+ lots per auction, this caused workers to hang indefinitely on socket reads to WPMU DEV servers (32.193.94.25,32.193.93.106). AddedWP_IMPORTINGconstant at the REST worker entry point and apre_http_requestfilter inCatalogSyncWorkerthat blocks all non-essential external HTTP during the batch post-insertion phase. Loopback (127.0.0.1,localhost) and BidSpirit API calls remain allowed. - Stuck staging rows after force-kill — When workers were force-killed mid-sync, staging rows in
import_historywere left withsyncstart=1and never unblocked. Subsequent sync runs could not see these rows (filtered out byLot::getRawLots()), causing the InsertLotsBS loop to exit immediately with 0 posts processed. Combined with job deduplication (SyncQueue::enqueue()skips if aprocessingjob exists), this created a deadlock where no new sync could proceed.
Files Changed
- Modified:
auctionforge.php,inc/sync/CatalogSyncWorker.php
---
[3.2.2] — 2026-03-17
Full Sync Auction Discovery Fix
Fixes
- Full Sync finds no auctions on fresh sites — The v3
full_syncaction only queried the WordPress database for existing auction terms, but on a freshly deployed site the database has zero auctions. AddedAuctionList::init()discovery step before querying the DB, so Full Sync now fetches all auctions from the BidSpirit API and creates taxonomy terms first, then enqueues catalog sync jobs for each.
Files Changed
- Modified:
auctionforge.php
---
[3.2.0] — 2026-03-14
Webhook Pipeline Fixes, Archive Sync & Admin UI Overhaul
New Features
- Archive Sync — New "Archive Sync" button on Sync Status admin page. Enqueues catalog sync jobs for all ARCHIVED/ENDED auctions. Past auctions now appear in the auction dropdown with an optgroup separator and state label.
- Sync Tasks v3 — Replaced old v2 task cards (importData, importBidSpirit, lotBidSpiritOld) with v3 queue-based tasks. "Sync Active Auctions" and "Sync Archived Auctions" now enqueue jobs via the queue system. Maintenance tasks (Clean Draft/Trash Lots, Clean Orphaned Meta) remain as direct-execution tasks.
- How It Works guide rewritten — Complete rewrite of the admin guide for v3 architecture. Documents webhook-first flow, all 5 job types, queue system mechanics, cron setup (external + WP-Cron), configuration constants, and troubleshooting.
Fixes
- Dual-write removed — Removed legacy handlers from
auctionCatalogUpdated(),auctionDayEnded(), anditemsUpdated()webhook methods. The old handlers were racing with the v3 worker, creating orphaned staging rows inimport_historythat were never processed. All three methods now exclusively use the v3 enqueue → spawn path. - ITEMS_UPDATED webhook — Fixed
itemsUpdated()failing to enqueue jobs. TheITEMS_UPDATEDpayload hasauctionIdnested initemsByLanguage.{lang}[0].item.auctionId, not at the top level. Added extraction logic to resolve it. - ItemUpdateWorker incomplete —
ItemUpdateWorker::process()was only callingLot::bulkSave()(staging table) without runningInsertLotsBSto process staged data into WP posts andbp_meta_data. Added the InsertLotsBS processing step with autocommit restore. Item updates now flow: stage → InsertLotsBS → WP post + meta → cache clear. - Worker spawn reliability — Changed
SyncQueue::spawnWorker()from non-blocking HTTPS to blocking HTTP loopback (http://127.0.0.1with explicitHostheader, 2s timeout). Fixes nginx 403/404 errors when HTTPS loopback hits the default vhost instead of the site's vhost. - API token constant — Plugin expects
AUCTIONFORGE_API_TOKENinwp-config.php(renamed fromUCO_API_TOKENduring the plugin rename). Documented in readme.
Database
- DB version: 22 → 23
Files Changed
- Modified:
inc/controllers/AuctionsAPI.php,inc/sync/ItemUpdateWorker.php,inc/sync/SyncQueue.php,auctionforge.php,admin/view/sync-status.php,readme.txt
---
[3.0.0] — 2025-03-14
New Feature: Webhook-First Sync Architecture (Sync v3)
Overview: Complete redesign of the BidSpirit data synchronisation pipeline. Replaces the old two-phase polling system (importBidSpirit every hour + importData every minute) with a webhook-driven job queue that processes data in near real-time.
Architecture
- 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: webhook → queue → background worker → WordPress posts. - Dual-write mode — During transition, webhooks enqueue jobs AND still run the legacy handlers. Once verified, legacy handlers can be removed cleanly.
- Job deduplication — Prevents duplicate work by checking for existing pending/processing jobs with the same auction_id + job_type.
New Components
- Job Queue System (
inc/sync/SyncQueue.php) — Priority-based FIFO queue with atomic job claiming, status tracking (pending/processing/completed/failed/skipped), worker PID tracking, and automatic stuck job recovery. - Sync Logger (
inc/sync/SyncLogger.php) — Real-time log table for admin console polling with level filtering (info/success/warning/error) and incremental cursor-based retrieval. - Catalog Sync Worker (
inc/sync/CatalogSyncWorker.php) — Processes catalog_sync, full_sync, and day_ended jobs by reusing existingLotList::singleRun()logic. - Item Update Worker (
inc/sync/ItemUpdateWorker.php) — Processes individual item_update jobs with the same logic as the webhookitemsUpdatedhandler. - Background Worker (
crontasks/syncWorker.php) — Async CLI process spawned by webhooks viaexec()or by the safety cron. Claims and processes queued jobs with a configurable timeout (default 240s). - Safety Net (
crontasks/syncSafety.php) — Hourly cron that resets stuck jobs (>10min), spawns workers for pending jobs, runs a 24-hour health check (auto-enqueues full sync if no webhooks received), and purges old data.
Admin UI
- Queue Status Dashboard — New card on Sync Status page showing pending/processing/completed/failed/skipped counts, recent jobs table with real-time refresh, worker status badge, and action buttons:
- Full Sync — Enqueues catalog sync for all active auctions
- Sync Selected — Enqueue a single auction from dropdown
- Spawn Worker — Manually trigger a background worker process
- Live Console — Dark-themed terminal console on the Sync Status page. Polls
af_sync_logevery 1.5s showing timestamped, color-coded log entries from webhooks, workers, queue operations, and the safety cron. Supports pause, clear, and auto-scroll.
Cron Changes
- Removed
importData(ran every minute — ~1,440 PHP executions/day) - Removed
importBidSpirit(ran hourly — ~24 PHP executions/day) - Added
syncSafety(runs hourly at :10 — 24 PHP executions/day) - Net effect: ~62 PHP executions/hour → 1 PHP execution/hour
- WP-Cron safety hook (
auctionforge_sync_safety) — Always-active hourly event, independent of external cron - setup.sh v3 — Updated task definitions, new
migratecommand for interactive v2→v3 transition
Database
- New table:
af_sync_queue— Job queue with status, priority, source, attempts, worker PID, timing columns - New table:
af_sync_log— Real-time log entries with context, level, auction_id, job_id - DB version: 20 → 22
Constants Added
| Constant | Default | Description |
|---|---|---|
|
AUCTIONFORGE_SYNC_WORKER_TIMEOUT| 240 | Worker process timeout in seconds ||
AUCTIONFORGE_SYNC_STALE_JOB| 600 | Seconds before a processing job is considered stuck ||
AUCTIONFORGE_SYNC_HEALTH_CHECK| 86400 | Seconds without webhook before triggering full sync ||
AUCTIONFORGE_SYNC_LOG_RETENTION| 7 | Days to keep log entries ||
AUCTIONFORGE_SYNC_QUEUE_RETENTION| 30 | Days to keep completed queue jobs ||
AUCTIONFORGE_CURL_TIMEOUT| 30 | BidSpirit API cURL timeout in seconds ||
AUCTIONFORGE_PHP_BINARY| /www/server/php/83/bin/php | PHP CLI binary path for spawning workers |AJAX Handlers Added
auctionforge_sync_log_poll— Incremental log polling for live consoleauctionforge_sync_queue_status— Queue counts + recent jobs for dashboardauctionforge_sync_enqueue— Admin-triggered sync actions (full_sync, sync_auction, spawn_worker)
Fixes
- cURL timeout — BidSpiritRequest now enforces a 30-second timeout (was unlimited/0), preventing hung connections from blocking the sync pipeline.
Files Changed
- Modified:
auctionforge.php,inc/coreIncludes.php,inc/controllers/AuctionsAPI.php,inc/BidSpiritRequest.php,admin/view/sync-status.php,crontasks/setup.sh - Created:
inc/sync/SyncQueue.php,inc/sync/SyncLogger.php,inc/sync/CatalogSyncWorker.php,inc/sync/ItemUpdateWorker.php,crontasks/syncWorker.php,crontasks/syncSafety.php
---
[2.7.3.0]
Fixes
- Various stability improvements and bug fixes.
[2.7.1.2]
Fixes
- Added missing
vatAndCommission()function inloadBid()— the sales tax display on single lot pages was never being rendered because the code to callloadTemplateforvat-and-commission-templatewas missing fromapp.js.
[2.7.1.1]
Fixes
- 2 decimal places now only appear in the bid modal (Your max bid, Total Price) via
showDecimalsflag. 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.
[2.7.0.9]
Fixes
- Fixed fatal error during plugin install/upgrade:
class-stats-database.phprequire failure.
[2.7.0.0]
New Features: Advanced Lot Analytics
- Conversion Tracking, Peak Viewing Times, Pre-Sale vs Live Comparison, Category Performance, Share Analytics, Search → View Funnel, Click-Through Tracking, CSV Export, Hot Lot Badge.
- New DB table:
af_lot_shares. New columns onaf_lot_analytics. DB version bumped to 20.
[2.6.0.0]
New Feature: Lot Analytics
- Comprehensive lot view and favorite tracking system with admin dashboard.
[2.5.0.0]
New Features
- Site Statistics System — Full website analytics built into the plugin admin.
- Recently Viewed Items — Profile page tab showing last 20 viewed lots per user.
- CATALOG_PUBLISHED webhook now triggers catalog sync — Previously only sent push notifications without syncing lots. When the earlier AUCTION_CATALOG_UPDATED fired before the catalog was ready on BidSpirit, lots were never imported. CATALOG_PUBLISHED now calls
-
v3.2.5.5 Stable Mar 24, 2026Download v3.2.5.5📦 4.85 MB⚙️ WP 5.2+🔧 PHP 7.2+✓ Tested 6.4
AuctionForge Changelog
All notable changes to the AuctionForge plugin are documented in this file.
---
[3.2.5] — 2026-03-19
Sync Reliability & Stuck Lot Prevention
Fixes
- CATALOG_PUBLISHED webhook now triggers catalog sync — Previously only sent push notifications without syncing lots. When the earlier AUCTION_CATALOG_UPDATED fired before the catalog was ready on BidSpirit, lots were never imported. CATALOG_PUBLISHED now calls
auctionCatalogUpdated()to trigger a full catalog sync when the catalog is actually available. - 0-lot API results now fail instead of silently succeeding — When BidSpirit API returns 0 lots (catalog not yet ready), the sync job now fails with an explicit error message, allowing the next webhook to create a fresh retry job.
- Expanded CDN allowlist in pre_http_request filter — The HTTP filter during bulk post insertion now allows all
*.bidspirit.comsubdomains and BidSpirit image CDNs (fastly.net,cloudfront.net). Previously onlybidspirit.comandwww.bidspirit.comwere allowed, blocking image downloads during sync and causing worker hangs. - InsertLotsBS timeout guard — Stage 5 (InsertLotsBS processing loop) now has a 180-second timeout and logs progress every 2 batches. Prevents indefinite hangs that previously required manual force-kill.
- fixResult() no longer marks lots as done when postId=0 — When
lotProcessing()fails to create a WP post, the staging row now keepssyncFinished=0so the lot is retried on the next sync pass, instead of being permanently marked as complete with no actual post. - lotProcessing() logs error on missing auction term — Previously returned 0 silently when
Auction::findAuctionById()failed. Now logs an explicit error that feeds intofixResult()to keep the lot retryable. - Hourly orphan detection in safety cron — New step in
syncSafety.phpdetects lot posts that exist inbp_meta_databut are missing their auction taxonomy assignment (caused by workers killed mid-batch) and auto-repairs them withwp_set_object_terms().
Files Changed
- Modified:
inc/controllers/AuctionsAPI.php,inc/sync/CatalogSyncWorker.php,inc/abs/InsertLotsAbstract.php,inc/import/InsertLotsBS.php,crontasks/syncSafety.php
---
[3.2.4] — 2026-03-18
Sync Worker Hang Fix
Fixes
- Sync workers hanging at InsertLotsBS stage — Third-party plugins (Smush Pro, SmartCrawl SEO, WPMU DEV Updates) hook into
wp_insert_post()and make blocking outbound HTTPS calls for every lot processed. With 489+ lots per auction, this caused workers to hang indefinitely on socket reads to WPMU DEV servers (32.193.94.25,32.193.93.106). AddedWP_IMPORTINGconstant at the REST worker entry point and apre_http_requestfilter inCatalogSyncWorkerthat blocks all non-essential external HTTP during the batch post-insertion phase. Loopback (127.0.0.1,localhost) and BidSpirit API calls remain allowed. - Stuck staging rows after force-kill — When workers were force-killed mid-sync, staging rows in
import_historywere left withsyncstart=1and never unblocked. Subsequent sync runs could not see these rows (filtered out byLot::getRawLots()), causing the InsertLotsBS loop to exit immediately with 0 posts processed. Combined with job deduplication (SyncQueue::enqueue()skips if aprocessingjob exists), this created a deadlock where no new sync could proceed.
Files Changed
- Modified:
auctionforge.php,inc/sync/CatalogSyncWorker.php
---
[3.2.2] — 2026-03-17
Full Sync Auction Discovery Fix
Fixes
- Full Sync finds no auctions on fresh sites — The v3
full_syncaction only queried the WordPress database for existing auction terms, but on a freshly deployed site the database has zero auctions. AddedAuctionList::init()discovery step before querying the DB, so Full Sync now fetches all auctions from the BidSpirit API and creates taxonomy terms first, then enqueues catalog sync jobs for each.
Files Changed
- Modified:
auctionforge.php
---
[3.2.0] — 2026-03-14
Webhook Pipeline Fixes, Archive Sync & Admin UI Overhaul
New Features
- Archive Sync — New "Archive Sync" button on Sync Status admin page. Enqueues catalog sync jobs for all ARCHIVED/ENDED auctions. Past auctions now appear in the auction dropdown with an optgroup separator and state label.
- Sync Tasks v3 — Replaced old v2 task cards (importData, importBidSpirit, lotBidSpiritOld) with v3 queue-based tasks. "Sync Active Auctions" and "Sync Archived Auctions" now enqueue jobs via the queue system. Maintenance tasks (Clean Draft/Trash Lots, Clean Orphaned Meta) remain as direct-execution tasks.
- How It Works guide rewritten — Complete rewrite of the admin guide for v3 architecture. Documents webhook-first flow, all 5 job types, queue system mechanics, cron setup (external + WP-Cron), configuration constants, and troubleshooting.
Fixes
- Dual-write removed — Removed legacy handlers from
auctionCatalogUpdated(),auctionDayEnded(), anditemsUpdated()webhook methods. The old handlers were racing with the v3 worker, creating orphaned staging rows inimport_historythat were never processed. All three methods now exclusively use the v3 enqueue → spawn path. - ITEMS_UPDATED webhook — Fixed
itemsUpdated()failing to enqueue jobs. TheITEMS_UPDATEDpayload hasauctionIdnested initemsByLanguage.{lang}[0].item.auctionId, not at the top level. Added extraction logic to resolve it. - ItemUpdateWorker incomplete —
ItemUpdateWorker::process()was only callingLot::bulkSave()(staging table) without runningInsertLotsBSto process staged data into WP posts andbp_meta_data. Added the InsertLotsBS processing step with autocommit restore. Item updates now flow: stage → InsertLotsBS → WP post + meta → cache clear. - Worker spawn reliability — Changed
SyncQueue::spawnWorker()from non-blocking HTTPS to blocking HTTP loopback (http://127.0.0.1with explicitHostheader, 2s timeout). Fixes nginx 403/404 errors when HTTPS loopback hits the default vhost instead of the site's vhost. - API token constant — Plugin expects
AUCTIONFORGE_API_TOKENinwp-config.php(renamed fromUCO_API_TOKENduring the plugin rename). Documented in readme.
Database
- DB version: 22 → 23
Files Changed
- Modified:
inc/controllers/AuctionsAPI.php,inc/sync/ItemUpdateWorker.php,inc/sync/SyncQueue.php,auctionforge.php,admin/view/sync-status.php,readme.txt
---
[3.0.0] — 2025-03-14
New Feature: Webhook-First Sync Architecture (Sync v3)
Overview: Complete redesign of the BidSpirit data synchronisation pipeline. Replaces the old two-phase polling system (importBidSpirit every hour + importData every minute) with a webhook-driven job queue that processes data in near real-time.
Architecture
- 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: webhook → queue → background worker → WordPress posts. - Dual-write mode — During transition, webhooks enqueue jobs AND still run the legacy handlers. Once verified, legacy handlers can be removed cleanly.
- Job deduplication — Prevents duplicate work by checking for existing pending/processing jobs with the same auction_id + job_type.
New Components
- Job Queue System (
inc/sync/SyncQueue.php) — Priority-based FIFO queue with atomic job claiming, status tracking (pending/processing/completed/failed/skipped), worker PID tracking, and automatic stuck job recovery. - Sync Logger (
inc/sync/SyncLogger.php) — Real-time log table for admin console polling with level filtering (info/success/warning/error) and incremental cursor-based retrieval. - Catalog Sync Worker (
inc/sync/CatalogSyncWorker.php) — Processes catalog_sync, full_sync, and day_ended jobs by reusing existingLotList::singleRun()logic. - Item Update Worker (
inc/sync/ItemUpdateWorker.php) — Processes individual item_update jobs with the same logic as the webhookitemsUpdatedhandler. - Background Worker (
crontasks/syncWorker.php) — Async CLI process spawned by webhooks viaexec()or by the safety cron. Claims and processes queued jobs with a configurable timeout (default 240s). - Safety Net (
crontasks/syncSafety.php) — Hourly cron that resets stuck jobs (>10min), spawns workers for pending jobs, runs a 24-hour health check (auto-enqueues full sync if no webhooks received), and purges old data.
Admin UI
- Queue Status Dashboard — New card on Sync Status page showing pending/processing/completed/failed/skipped counts, recent jobs table with real-time refresh, worker status badge, and action buttons:
- Full Sync — Enqueues catalog sync for all active auctions
- Sync Selected — Enqueue a single auction from dropdown
- Spawn Worker — Manually trigger a background worker process
- Live Console — Dark-themed terminal console on the Sync Status page. Polls
af_sync_logevery 1.5s showing timestamped, color-coded log entries from webhooks, workers, queue operations, and the safety cron. Supports pause, clear, and auto-scroll.
Cron Changes
- Removed
importData(ran every minute — ~1,440 PHP executions/day) - Removed
importBidSpirit(ran hourly — ~24 PHP executions/day) - Added
syncSafety(runs hourly at :10 — 24 PHP executions/day) - Net effect: ~62 PHP executions/hour → 1 PHP execution/hour
- WP-Cron safety hook (
auctionforge_sync_safety) — Always-active hourly event, independent of external cron - setup.sh v3 — Updated task definitions, new
migratecommand for interactive v2→v3 transition
Database
- New table:
af_sync_queue— Job queue with status, priority, source, attempts, worker PID, timing columns - New table:
af_sync_log— Real-time log entries with context, level, auction_id, job_id - DB version: 20 → 22
Constants Added
| Constant | Default | Description |
|---|---|---|
|
AUCTIONFORGE_SYNC_WORKER_TIMEOUT| 240 | Worker process timeout in seconds ||
AUCTIONFORGE_SYNC_STALE_JOB| 600 | Seconds before a processing job is considered stuck ||
AUCTIONFORGE_SYNC_HEALTH_CHECK| 86400 | Seconds without webhook before triggering full sync ||
AUCTIONFORGE_SYNC_LOG_RETENTION| 7 | Days to keep log entries ||
AUCTIONFORGE_SYNC_QUEUE_RETENTION| 30 | Days to keep completed queue jobs ||
AUCTIONFORGE_CURL_TIMEOUT| 30 | BidSpirit API cURL timeout in seconds ||
AUCTIONFORGE_PHP_BINARY| /www/server/php/83/bin/php | PHP CLI binary path for spawning workers |AJAX Handlers Added
auctionforge_sync_log_poll— Incremental log polling for live consoleauctionforge_sync_queue_status— Queue counts + recent jobs for dashboardauctionforge_sync_enqueue— Admin-triggered sync actions (full_sync, sync_auction, spawn_worker)
Fixes
- cURL timeout — BidSpiritRequest now enforces a 30-second timeout (was unlimited/0), preventing hung connections from blocking the sync pipeline.
Files Changed
- Modified:
auctionforge.php,inc/coreIncludes.php,inc/controllers/AuctionsAPI.php,inc/BidSpiritRequest.php,admin/view/sync-status.php,crontasks/setup.sh - Created:
inc/sync/SyncQueue.php,inc/sync/SyncLogger.php,inc/sync/CatalogSyncWorker.php,inc/sync/ItemUpdateWorker.php,crontasks/syncWorker.php,crontasks/syncSafety.php
---
[2.7.3.0]
Fixes
- Various stability improvements and bug fixes.
[2.7.1.2]
Fixes
- Added missing
vatAndCommission()function inloadBid()— the sales tax display on single lot pages was never being rendered because the code to callloadTemplateforvat-and-commission-templatewas missing fromapp.js.
[2.7.1.1]
Fixes
- 2 decimal places now only appear in the bid modal (Your max bid, Total Price) via
showDecimalsflag. 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.
[2.7.0.9]
Fixes
- Fixed fatal error during plugin install/upgrade:
class-stats-database.phprequire failure.
[2.7.0.0]
New Features: Advanced Lot Analytics
- Conversion Tracking, Peak Viewing Times, Pre-Sale vs Live Comparison, Category Performance, Share Analytics, Search → View Funnel, Click-Through Tracking, CSV Export, Hot Lot Badge.
- New DB table:
af_lot_shares. New columns onaf_lot_analytics. DB version bumped to 20.
[2.6.0.0]
New Feature: Lot Analytics
- Comprehensive lot view and favorite tracking system with admin dashboard.
[2.5.0.0]
New Features
- Site Statistics System — Full website analytics built into the plugin admin.
- Recently Viewed Items — Profile page tab showing last 20 viewed lots per user.
- CATALOG_PUBLISHED webhook now triggers catalog sync — Previously only sent push notifications without syncing lots. When the earlier AUCTION_CATALOG_UPDATED fired before the catalog was ready on BidSpirit, lots were never imported. CATALOG_PUBLISHED now calls
-
v3.2.5.4 Stable Mar 24, 2026Download v3.2.5.4📦 4.85 MB⚙️ WP 5.2+🔧 PHP 7.2+✓ Tested 6.4
AuctionForge Changelog
All notable changes to the AuctionForge plugin are documented in this file.
---
[3.2.5] — 2026-03-19
Sync Reliability & Stuck Lot Prevention
Fixes
- CATALOG_PUBLISHED webhook now triggers catalog sync — Previously only sent push notifications without syncing lots. When the earlier AUCTION_CATALOG_UPDATED fired before the catalog was ready on BidSpirit, lots were never imported. CATALOG_PUBLISHED now calls
auctionCatalogUpdated()to trigger a full catalog sync when the catalog is actually available. - 0-lot API results now fail instead of silently succeeding — When BidSpirit API returns 0 lots (catalog not yet ready), the sync job now fails with an explicit error message, allowing the next webhook to create a fresh retry job.
- Expanded CDN allowlist in pre_http_request filter — The HTTP filter during bulk post insertion now allows all
*.bidspirit.comsubdomains and BidSpirit image CDNs (fastly.net,cloudfront.net). Previously onlybidspirit.comandwww.bidspirit.comwere allowed, blocking image downloads during sync and causing worker hangs. - InsertLotsBS timeout guard — Stage 5 (InsertLotsBS processing loop) now has a 180-second timeout and logs progress every 2 batches. Prevents indefinite hangs that previously required manual force-kill.
- fixResult() no longer marks lots as done when postId=0 — When
lotProcessing()fails to create a WP post, the staging row now keepssyncFinished=0so the lot is retried on the next sync pass, instead of being permanently marked as complete with no actual post. - lotProcessing() logs error on missing auction term — Previously returned 0 silently when
Auction::findAuctionById()failed. Now logs an explicit error that feeds intofixResult()to keep the lot retryable. - Hourly orphan detection in safety cron — New step in
syncSafety.phpdetects lot posts that exist inbp_meta_databut are missing their auction taxonomy assignment (caused by workers killed mid-batch) and auto-repairs them withwp_set_object_terms().
Files Changed
- Modified:
inc/controllers/AuctionsAPI.php,inc/sync/CatalogSyncWorker.php,inc/abs/InsertLotsAbstract.php,inc/import/InsertLotsBS.php,crontasks/syncSafety.php
---
[3.2.4] — 2026-03-18
Sync Worker Hang Fix
Fixes
- Sync workers hanging at InsertLotsBS stage — Third-party plugins (Smush Pro, SmartCrawl SEO, WPMU DEV Updates) hook into
wp_insert_post()and make blocking outbound HTTPS calls for every lot processed. With 489+ lots per auction, this caused workers to hang indefinitely on socket reads to WPMU DEV servers (32.193.94.25,32.193.93.106). AddedWP_IMPORTINGconstant at the REST worker entry point and apre_http_requestfilter inCatalogSyncWorkerthat blocks all non-essential external HTTP during the batch post-insertion phase. Loopback (127.0.0.1,localhost) and BidSpirit API calls remain allowed. - Stuck staging rows after force-kill — When workers were force-killed mid-sync, staging rows in
import_historywere left withsyncstart=1and never unblocked. Subsequent sync runs could not see these rows (filtered out byLot::getRawLots()), causing the InsertLotsBS loop to exit immediately with 0 posts processed. Combined with job deduplication (SyncQueue::enqueue()skips if aprocessingjob exists), this created a deadlock where no new sync could proceed.
Files Changed
- Modified:
auctionforge.php,inc/sync/CatalogSyncWorker.php
---
[3.2.2] — 2026-03-17
Full Sync Auction Discovery Fix
Fixes
- Full Sync finds no auctions on fresh sites — The v3
full_syncaction only queried the WordPress database for existing auction terms, but on a freshly deployed site the database has zero auctions. AddedAuctionList::init()discovery step before querying the DB, so Full Sync now fetches all auctions from the BidSpirit API and creates taxonomy terms first, then enqueues catalog sync jobs for each.
Files Changed
- Modified:
auctionforge.php
---
[3.2.0] — 2026-03-14
Webhook Pipeline Fixes, Archive Sync & Admin UI Overhaul
New Features
- Archive Sync — New "Archive Sync" button on Sync Status admin page. Enqueues catalog sync jobs for all ARCHIVED/ENDED auctions. Past auctions now appear in the auction dropdown with an optgroup separator and state label.
- Sync Tasks v3 — Replaced old v2 task cards (importData, importBidSpirit, lotBidSpiritOld) with v3 queue-based tasks. "Sync Active Auctions" and "Sync Archived Auctions" now enqueue jobs via the queue system. Maintenance tasks (Clean Draft/Trash Lots, Clean Orphaned Meta) remain as direct-execution tasks.
- How It Works guide rewritten — Complete rewrite of the admin guide for v3 architecture. Documents webhook-first flow, all 5 job types, queue system mechanics, cron setup (external + WP-Cron), configuration constants, and troubleshooting.
Fixes
- Dual-write removed — Removed legacy handlers from
auctionCatalogUpdated(),auctionDayEnded(), anditemsUpdated()webhook methods. The old handlers were racing with the v3 worker, creating orphaned staging rows inimport_historythat were never processed. All three methods now exclusively use the v3 enqueue → spawn path. - ITEMS_UPDATED webhook — Fixed
itemsUpdated()failing to enqueue jobs. TheITEMS_UPDATEDpayload hasauctionIdnested initemsByLanguage.{lang}[0].item.auctionId, not at the top level. Added extraction logic to resolve it. - ItemUpdateWorker incomplete —
ItemUpdateWorker::process()was only callingLot::bulkSave()(staging table) without runningInsertLotsBSto process staged data into WP posts andbp_meta_data. Added the InsertLotsBS processing step with autocommit restore. Item updates now flow: stage → InsertLotsBS → WP post + meta → cache clear. - Worker spawn reliability — Changed
SyncQueue::spawnWorker()from non-blocking HTTPS to blocking HTTP loopback (http://127.0.0.1with explicitHostheader, 2s timeout). Fixes nginx 403/404 errors when HTTPS loopback hits the default vhost instead of the site's vhost. - API token constant — Plugin expects
AUCTIONFORGE_API_TOKENinwp-config.php(renamed fromUCO_API_TOKENduring the plugin rename). Documented in readme.
Database
- DB version: 22 → 23
Files Changed
- Modified:
inc/controllers/AuctionsAPI.php,inc/sync/ItemUpdateWorker.php,inc/sync/SyncQueue.php,auctionforge.php,admin/view/sync-status.php,readme.txt
---
[3.0.0] — 2025-03-14
New Feature: Webhook-First Sync Architecture (Sync v3)
Overview: Complete redesign of the BidSpirit data synchronisation pipeline. Replaces the old two-phase polling system (importBidSpirit every hour + importData every minute) with a webhook-driven job queue that processes data in near real-time.
Architecture
- 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: webhook → queue → background worker → WordPress posts. - Dual-write mode — During transition, webhooks enqueue jobs AND still run the legacy handlers. Once verified, legacy handlers can be removed cleanly.
- Job deduplication — Prevents duplicate work by checking for existing pending/processing jobs with the same auction_id + job_type.
New Components
- Job Queue System (
inc/sync/SyncQueue.php) — Priority-based FIFO queue with atomic job claiming, status tracking (pending/processing/completed/failed/skipped), worker PID tracking, and automatic stuck job recovery. - Sync Logger (
inc/sync/SyncLogger.php) — Real-time log table for admin console polling with level filtering (info/success/warning/error) and incremental cursor-based retrieval. - Catalog Sync Worker (
inc/sync/CatalogSyncWorker.php) — Processes catalog_sync, full_sync, and day_ended jobs by reusing existingLotList::singleRun()logic. - Item Update Worker (
inc/sync/ItemUpdateWorker.php) — Processes individual item_update jobs with the same logic as the webhookitemsUpdatedhandler. - Background Worker (
crontasks/syncWorker.php) — Async CLI process spawned by webhooks viaexec()or by the safety cron. Claims and processes queued jobs with a configurable timeout (default 240s). - Safety Net (
crontasks/syncSafety.php) — Hourly cron that resets stuck jobs (>10min), spawns workers for pending jobs, runs a 24-hour health check (auto-enqueues full sync if no webhooks received), and purges old data.
Admin UI
- Queue Status Dashboard — New card on Sync Status page showing pending/processing/completed/failed/skipped counts, recent jobs table with real-time refresh, worker status badge, and action buttons:
- Full Sync — Enqueues catalog sync for all active auctions
- Sync Selected — Enqueue a single auction from dropdown
- Spawn Worker — Manually trigger a background worker process
- Live Console — Dark-themed terminal console on the Sync Status page. Polls
af_sync_logevery 1.5s showing timestamped, color-coded log entries from webhooks, workers, queue operations, and the safety cron. Supports pause, clear, and auto-scroll.
Cron Changes
- Removed
importData(ran every minute — ~1,440 PHP executions/day) - Removed
importBidSpirit(ran hourly — ~24 PHP executions/day) - Added
syncSafety(runs hourly at :10 — 24 PHP executions/day) - Net effect: ~62 PHP executions/hour → 1 PHP execution/hour
- WP-Cron safety hook (
auctionforge_sync_safety) — Always-active hourly event, independent of external cron - setup.sh v3 — Updated task definitions, new
migratecommand for interactive v2→v3 transition
Database
- New table:
af_sync_queue— Job queue with status, priority, source, attempts, worker PID, timing columns - New table:
af_sync_log— Real-time log entries with context, level, auction_id, job_id - DB version: 20 → 22
Constants Added
| Constant | Default | Description |
|---|---|---|
|
AUCTIONFORGE_SYNC_WORKER_TIMEOUT| 240 | Worker process timeout in seconds ||
AUCTIONFORGE_SYNC_STALE_JOB| 600 | Seconds before a processing job is considered stuck ||
AUCTIONFORGE_SYNC_HEALTH_CHECK| 86400 | Seconds without webhook before triggering full sync ||
AUCTIONFORGE_SYNC_LOG_RETENTION| 7 | Days to keep log entries ||
AUCTIONFORGE_SYNC_QUEUE_RETENTION| 30 | Days to keep completed queue jobs ||
AUCTIONFORGE_CURL_TIMEOUT| 30 | BidSpirit API cURL timeout in seconds ||
AUCTIONFORGE_PHP_BINARY| /www/server/php/83/bin/php | PHP CLI binary path for spawning workers |AJAX Handlers Added
auctionforge_sync_log_poll— Incremental log polling for live consoleauctionforge_sync_queue_status— Queue counts + recent jobs for dashboardauctionforge_sync_enqueue— Admin-triggered sync actions (full_sync, sync_auction, spawn_worker)
Fixes
- cURL timeout — BidSpiritRequest now enforces a 30-second timeout (was unlimited/0), preventing hung connections from blocking the sync pipeline.
Files Changed
- Modified:
auctionforge.php,inc/coreIncludes.php,inc/controllers/AuctionsAPI.php,inc/BidSpiritRequest.php,admin/view/sync-status.php,crontasks/setup.sh - Created:
inc/sync/SyncQueue.php,inc/sync/SyncLogger.php,inc/sync/CatalogSyncWorker.php,inc/sync/ItemUpdateWorker.php,crontasks/syncWorker.php,crontasks/syncSafety.php
---
[2.7.3.0]
Fixes
- Various stability improvements and bug fixes.
[2.7.1.2]
Fixes
- Added missing
vatAndCommission()function inloadBid()— the sales tax display on single lot pages was never being rendered because the code to callloadTemplateforvat-and-commission-templatewas missing fromapp.js.
[2.7.1.1]
Fixes
- 2 decimal places now only appear in the bid modal (Your max bid, Total Price) via
showDecimalsflag. 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.
[2.7.0.9]
Fixes
- Fixed fatal error during plugin install/upgrade:
class-stats-database.phprequire failure.
[2.7.0.0]
New Features: Advanced Lot Analytics
- Conversion Tracking, Peak Viewing Times, Pre-Sale vs Live Comparison, Category Performance, Share Analytics, Search → View Funnel, Click-Through Tracking, CSV Export, Hot Lot Badge.
- New DB table:
af_lot_shares. New columns onaf_lot_analytics. DB version bumped to 20.
[2.6.0.0]
New Feature: Lot Analytics
- Comprehensive lot view and favorite tracking system with admin dashboard.
[2.5.0.0]
New Features
- Site Statistics System — Full website analytics built into the plugin admin.
- Recently Viewed Items — Profile page tab showing last 20 viewed lots per user.
- CATALOG_PUBLISHED webhook now triggers catalog sync — Previously only sent push notifications without syncing lots. When the earlier AUCTION_CATALOG_UPDATED fired before the catalog was ready on BidSpirit, lots were never imported. CATALOG_PUBLISHED now calls
-
v3.2.5.2 Stable Mar 23, 2026Download v3.2.5.2📦 4.85 MB⚙️ WP 5.2+🔧 PHP 7.2+✓ Tested 6.4
AuctionForge Changelog
All notable changes to the AuctionForge plugin are documented in this file.
---
[3.2.5] — 2026-03-19
Sync Reliability & Stuck Lot Prevention
Fixes
- CATALOG_PUBLISHED webhook now triggers catalog sync — Previously only sent push notifications without syncing lots. When the earlier AUCTION_CATALOG_UPDATED fired before the catalog was ready on BidSpirit, lots were never imported. CATALOG_PUBLISHED now calls
auctionCatalogUpdated()to trigger a full catalog sync when the catalog is actually available. - 0-lot API results now fail instead of silently succeeding — When BidSpirit API returns 0 lots (catalog not yet ready), the sync job now fails with an explicit error message, allowing the next webhook to create a fresh retry job.
- Expanded CDN allowlist in pre_http_request filter — The HTTP filter during bulk post insertion now allows all
*.bidspirit.comsubdomains and BidSpirit image CDNs (fastly.net,cloudfront.net). Previously onlybidspirit.comandwww.bidspirit.comwere allowed, blocking image downloads during sync and causing worker hangs. - InsertLotsBS timeout guard — Stage 5 (InsertLotsBS processing loop) now has a 180-second timeout and logs progress every 2 batches. Prevents indefinite hangs that previously required manual force-kill.
- fixResult() no longer marks lots as done when postId=0 — When
lotProcessing()fails to create a WP post, the staging row now keepssyncFinished=0so the lot is retried on the next sync pass, instead of being permanently marked as complete with no actual post. - lotProcessing() logs error on missing auction term — Previously returned 0 silently when
Auction::findAuctionById()failed. Now logs an explicit error that feeds intofixResult()to keep the lot retryable. - Hourly orphan detection in safety cron — New step in
syncSafety.phpdetects lot posts that exist inbp_meta_databut are missing their auction taxonomy assignment (caused by workers killed mid-batch) and auto-repairs them withwp_set_object_terms().
Files Changed
- Modified:
inc/controllers/AuctionsAPI.php,inc/sync/CatalogSyncWorker.php,inc/abs/InsertLotsAbstract.php,inc/import/InsertLotsBS.php,crontasks/syncSafety.php
---
[3.2.4] — 2026-03-18
Sync Worker Hang Fix
Fixes
- Sync workers hanging at InsertLotsBS stage — Third-party plugins (Smush Pro, SmartCrawl SEO, WPMU DEV Updates) hook into
wp_insert_post()and make blocking outbound HTTPS calls for every lot processed. With 489+ lots per auction, this caused workers to hang indefinitely on socket reads to WPMU DEV servers (32.193.94.25,32.193.93.106). AddedWP_IMPORTINGconstant at the REST worker entry point and apre_http_requestfilter inCatalogSyncWorkerthat blocks all non-essential external HTTP during the batch post-insertion phase. Loopback (127.0.0.1,localhost) and BidSpirit API calls remain allowed. - Stuck staging rows after force-kill — When workers were force-killed mid-sync, staging rows in
import_historywere left withsyncstart=1and never unblocked. Subsequent sync runs could not see these rows (filtered out byLot::getRawLots()), causing the InsertLotsBS loop to exit immediately with 0 posts processed. Combined with job deduplication (SyncQueue::enqueue()skips if aprocessingjob exists), this created a deadlock where no new sync could proceed.
Files Changed
- Modified:
auctionforge.php,inc/sync/CatalogSyncWorker.php
---
[3.2.2] — 2026-03-17
Full Sync Auction Discovery Fix
Fixes
- Full Sync finds no auctions on fresh sites — The v3
full_syncaction only queried the WordPress database for existing auction terms, but on a freshly deployed site the database has zero auctions. AddedAuctionList::init()discovery step before querying the DB, so Full Sync now fetches all auctions from the BidSpirit API and creates taxonomy terms first, then enqueues catalog sync jobs for each.
Files Changed
- Modified:
auctionforge.php
---
[3.2.0] — 2026-03-14
Webhook Pipeline Fixes, Archive Sync & Admin UI Overhaul
New Features
- Archive Sync — New "Archive Sync" button on Sync Status admin page. Enqueues catalog sync jobs for all ARCHIVED/ENDED auctions. Past auctions now appear in the auction dropdown with an optgroup separator and state label.
- Sync Tasks v3 — Replaced old v2 task cards (importData, importBidSpirit, lotBidSpiritOld) with v3 queue-based tasks. "Sync Active Auctions" and "Sync Archived Auctions" now enqueue jobs via the queue system. Maintenance tasks (Clean Draft/Trash Lots, Clean Orphaned Meta) remain as direct-execution tasks.
- How It Works guide rewritten — Complete rewrite of the admin guide for v3 architecture. Documents webhook-first flow, all 5 job types, queue system mechanics, cron setup (external + WP-Cron), configuration constants, and troubleshooting.
Fixes
- Dual-write removed — Removed legacy handlers from
auctionCatalogUpdated(),auctionDayEnded(), anditemsUpdated()webhook methods. The old handlers were racing with the v3 worker, creating orphaned staging rows inimport_historythat were never processed. All three methods now exclusively use the v3 enqueue → spawn path. - ITEMS_UPDATED webhook — Fixed
itemsUpdated()failing to enqueue jobs. TheITEMS_UPDATEDpayload hasauctionIdnested initemsByLanguage.{lang}[0].item.auctionId, not at the top level. Added extraction logic to resolve it. - ItemUpdateWorker incomplete —
ItemUpdateWorker::process()was only callingLot::bulkSave()(staging table) without runningInsertLotsBSto process staged data into WP posts andbp_meta_data. Added the InsertLotsBS processing step with autocommit restore. Item updates now flow: stage → InsertLotsBS → WP post + meta → cache clear. - Worker spawn reliability — Changed
SyncQueue::spawnWorker()from non-blocking HTTPS to blocking HTTP loopback (http://127.0.0.1with explicitHostheader, 2s timeout). Fixes nginx 403/404 errors when HTTPS loopback hits the default vhost instead of the site's vhost. - API token constant — Plugin expects
AUCTIONFORGE_API_TOKENinwp-config.php(renamed fromUCO_API_TOKENduring the plugin rename). Documented in readme.
Database
- DB version: 22 → 23
Files Changed
- Modified:
inc/controllers/AuctionsAPI.php,inc/sync/ItemUpdateWorker.php,inc/sync/SyncQueue.php,auctionforge.php,admin/view/sync-status.php,readme.txt
---
[3.0.0] — 2025-03-14
New Feature: Webhook-First Sync Architecture (Sync v3)
Overview: Complete redesign of the BidSpirit data synchronisation pipeline. Replaces the old two-phase polling system (importBidSpirit every hour + importData every minute) with a webhook-driven job queue that processes data in near real-time.
Architecture
- 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: webhook → queue → background worker → WordPress posts. - Dual-write mode — During transition, webhooks enqueue jobs AND still run the legacy handlers. Once verified, legacy handlers can be removed cleanly.
- Job deduplication — Prevents duplicate work by checking for existing pending/processing jobs with the same auction_id + job_type.
New Components
- Job Queue System (
inc/sync/SyncQueue.php) — Priority-based FIFO queue with atomic job claiming, status tracking (pending/processing/completed/failed/skipped), worker PID tracking, and automatic stuck job recovery. - Sync Logger (
inc/sync/SyncLogger.php) — Real-time log table for admin console polling with level filtering (info/success/warning/error) and incremental cursor-based retrieval. - Catalog Sync Worker (
inc/sync/CatalogSyncWorker.php) — Processes catalog_sync, full_sync, and day_ended jobs by reusing existingLotList::singleRun()logic. - Item Update Worker (
inc/sync/ItemUpdateWorker.php) — Processes individual item_update jobs with the same logic as the webhookitemsUpdatedhandler. - Background Worker (
crontasks/syncWorker.php) — Async CLI process spawned by webhooks viaexec()or by the safety cron. Claims and processes queued jobs with a configurable timeout (default 240s). - Safety Net (
crontasks/syncSafety.php) — Hourly cron that resets stuck jobs (>10min), spawns workers for pending jobs, runs a 24-hour health check (auto-enqueues full sync if no webhooks received), and purges old data.
Admin UI
- Queue Status Dashboard — New card on Sync Status page showing pending/processing/completed/failed/skipped counts, recent jobs table with real-time refresh, worker status badge, and action buttons:
- Full Sync — Enqueues catalog sync for all active auctions
- Sync Selected — Enqueue a single auction from dropdown
- Spawn Worker — Manually trigger a background worker process
- Live Console — Dark-themed terminal console on the Sync Status page. Polls
af_sync_logevery 1.5s showing timestamped, color-coded log entries from webhooks, workers, queue operations, and the safety cron. Supports pause, clear, and auto-scroll.
Cron Changes
- Removed
importData(ran every minute — ~1,440 PHP executions/day) - Removed
importBidSpirit(ran hourly — ~24 PHP executions/day) - Added
syncSafety(runs hourly at :10 — 24 PHP executions/day) - Net effect: ~62 PHP executions/hour → 1 PHP execution/hour
- WP-Cron safety hook (
auctionforge_sync_safety) — Always-active hourly event, independent of external cron - setup.sh v3 — Updated task definitions, new
migratecommand for interactive v2→v3 transition
Database
- New table:
af_sync_queue— Job queue with status, priority, source, attempts, worker PID, timing columns - New table:
af_sync_log— Real-time log entries with context, level, auction_id, job_id - DB version: 20 → 22
Constants Added
| Constant | Default | Description |
|---|---|---|
|
AUCTIONFORGE_SYNC_WORKER_TIMEOUT| 240 | Worker process timeout in seconds ||
AUCTIONFORGE_SYNC_STALE_JOB| 600 | Seconds before a processing job is considered stuck ||
AUCTIONFORGE_SYNC_HEALTH_CHECK| 86400 | Seconds without webhook before triggering full sync ||
AUCTIONFORGE_SYNC_LOG_RETENTION| 7 | Days to keep log entries ||
AUCTIONFORGE_SYNC_QUEUE_RETENTION| 30 | Days to keep completed queue jobs ||
AUCTIONFORGE_CURL_TIMEOUT| 30 | BidSpirit API cURL timeout in seconds ||
AUCTIONFORGE_PHP_BINARY| /www/server/php/83/bin/php | PHP CLI binary path for spawning workers |AJAX Handlers Added
auctionforge_sync_log_poll— Incremental log polling for live consoleauctionforge_sync_queue_status— Queue counts + recent jobs for dashboardauctionforge_sync_enqueue— Admin-triggered sync actions (full_sync, sync_auction, spawn_worker)
Fixes
- cURL timeout — BidSpiritRequest now enforces a 30-second timeout (was unlimited/0), preventing hung connections from blocking the sync pipeline.
Files Changed
- Modified:
auctionforge.php,inc/coreIncludes.php,inc/controllers/AuctionsAPI.php,inc/BidSpiritRequest.php,admin/view/sync-status.php,crontasks/setup.sh - Created:
inc/sync/SyncQueue.php,inc/sync/SyncLogger.php,inc/sync/CatalogSyncWorker.php,inc/sync/ItemUpdateWorker.php,crontasks/syncWorker.php,crontasks/syncSafety.php
---
[2.7.3.0]
Fixes
- Various stability improvements and bug fixes.
[2.7.1.2]
Fixes
- Added missing
vatAndCommission()function inloadBid()— the sales tax display on single lot pages was never being rendered because the code to callloadTemplateforvat-and-commission-templatewas missing fromapp.js.
[2.7.1.1]
Fixes
- 2 decimal places now only appear in the bid modal (Your max bid, Total Price) via
showDecimalsflag. 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.
[2.7.0.9]
Fixes
- Fixed fatal error during plugin install/upgrade:
class-stats-database.phprequire failure.
[2.7.0.0]
New Features: Advanced Lot Analytics
- Conversion Tracking, Peak Viewing Times, Pre-Sale vs Live Comparison, Category Performance, Share Analytics, Search → View Funnel, Click-Through Tracking, CSV Export, Hot Lot Badge.
- New DB table:
af_lot_shares. New columns onaf_lot_analytics. DB version bumped to 20.
[2.6.0.0]
New Feature: Lot Analytics
- Comprehensive lot view and favorite tracking system with admin dashboard.
[2.5.0.0]
New Features
- Site Statistics System — Full website analytics built into the plugin admin.
- Recently Viewed Items — Profile page tab showing last 20 viewed lots per user.
- CATALOG_PUBLISHED webhook now triggers catalog sync — Previously only sent push notifications without syncing lots. When the earlier AUCTION_CATALOG_UPDATED fired before the catalog was ready on BidSpirit, lots were never imported. CATALOG_PUBLISHED now calls
-
v3.2.5.1 Stable Mar 23, 2026Download v3.2.5.1📦 4.85 MB⚙️ WP 5.2+🔧 PHP 7.2+✓ Tested 6.4
AuctionForge Changelog
All notable changes to the AuctionForge plugin are documented in this file.
---
[3.2.5] — 2026-03-19
Sync Reliability & Stuck Lot Prevention
Fixes
- CATALOG_PUBLISHED webhook now triggers catalog sync — Previously only sent push notifications without syncing lots. When the earlier AUCTION_CATALOG_UPDATED fired before the catalog was ready on BidSpirit, lots were never imported. CATALOG_PUBLISHED now calls
auctionCatalogUpdated()to trigger a full catalog sync when the catalog is actually available. - 0-lot API results now fail instead of silently succeeding — When BidSpirit API returns 0 lots (catalog not yet ready), the sync job now fails with an explicit error message, allowing the next webhook to create a fresh retry job.
- Expanded CDN allowlist in pre_http_request filter — The HTTP filter during bulk post insertion now allows all
*.bidspirit.comsubdomains and BidSpirit image CDNs (fastly.net,cloudfront.net). Previously onlybidspirit.comandwww.bidspirit.comwere allowed, blocking image downloads during sync and causing worker hangs. - InsertLotsBS timeout guard — Stage 5 (InsertLotsBS processing loop) now has a 180-second timeout and logs progress every 2 batches. Prevents indefinite hangs that previously required manual force-kill.
- fixResult() no longer marks lots as done when postId=0 — When
lotProcessing()fails to create a WP post, the staging row now keepssyncFinished=0so the lot is retried on the next sync pass, instead of being permanently marked as complete with no actual post. - lotProcessing() logs error on missing auction term — Previously returned 0 silently when
Auction::findAuctionById()failed. Now logs an explicit error that feeds intofixResult()to keep the lot retryable. - Hourly orphan detection in safety cron — New step in
syncSafety.phpdetects lot posts that exist inbp_meta_databut are missing their auction taxonomy assignment (caused by workers killed mid-batch) and auto-repairs them withwp_set_object_terms().
Files Changed
- Modified:
inc/controllers/AuctionsAPI.php,inc/sync/CatalogSyncWorker.php,inc/abs/InsertLotsAbstract.php,inc/import/InsertLotsBS.php,crontasks/syncSafety.php
---
[3.2.4] — 2026-03-18
Sync Worker Hang Fix
Fixes
- Sync workers hanging at InsertLotsBS stage — Third-party plugins (Smush Pro, SmartCrawl SEO, WPMU DEV Updates) hook into
wp_insert_post()and make blocking outbound HTTPS calls for every lot processed. With 489+ lots per auction, this caused workers to hang indefinitely on socket reads to WPMU DEV servers (32.193.94.25,32.193.93.106). AddedWP_IMPORTINGconstant at the REST worker entry point and apre_http_requestfilter inCatalogSyncWorkerthat blocks all non-essential external HTTP during the batch post-insertion phase. Loopback (127.0.0.1,localhost) and BidSpirit API calls remain allowed. - Stuck staging rows after force-kill — When workers were force-killed mid-sync, staging rows in
import_historywere left withsyncstart=1and never unblocked. Subsequent sync runs could not see these rows (filtered out byLot::getRawLots()), causing the InsertLotsBS loop to exit immediately with 0 posts processed. Combined with job deduplication (SyncQueue::enqueue()skips if aprocessingjob exists), this created a deadlock where no new sync could proceed.
Files Changed
- Modified:
auctionforge.php,inc/sync/CatalogSyncWorker.php
---
[3.2.2] — 2026-03-17
Full Sync Auction Discovery Fix
Fixes
- Full Sync finds no auctions on fresh sites — The v3
full_syncaction only queried the WordPress database for existing auction terms, but on a freshly deployed site the database has zero auctions. AddedAuctionList::init()discovery step before querying the DB, so Full Sync now fetches all auctions from the BidSpirit API and creates taxonomy terms first, then enqueues catalog sync jobs for each.
Files Changed
- Modified:
auctionforge.php
---
[3.2.0] — 2026-03-14
Webhook Pipeline Fixes, Archive Sync & Admin UI Overhaul
New Features
- Archive Sync — New "Archive Sync" button on Sync Status admin page. Enqueues catalog sync jobs for all ARCHIVED/ENDED auctions. Past auctions now appear in the auction dropdown with an optgroup separator and state label.
- Sync Tasks v3 — Replaced old v2 task cards (importData, importBidSpirit, lotBidSpiritOld) with v3 queue-based tasks. "Sync Active Auctions" and "Sync Archived Auctions" now enqueue jobs via the queue system. Maintenance tasks (Clean Draft/Trash Lots, Clean Orphaned Meta) remain as direct-execution tasks.
- How It Works guide rewritten — Complete rewrite of the admin guide for v3 architecture. Documents webhook-first flow, all 5 job types, queue system mechanics, cron setup (external + WP-Cron), configuration constants, and troubleshooting.
Fixes
- Dual-write removed — Removed legacy handlers from
auctionCatalogUpdated(),auctionDayEnded(), anditemsUpdated()webhook methods. The old handlers were racing with the v3 worker, creating orphaned staging rows inimport_historythat were never processed. All three methods now exclusively use the v3 enqueue → spawn path. - ITEMS_UPDATED webhook — Fixed
itemsUpdated()failing to enqueue jobs. TheITEMS_UPDATEDpayload hasauctionIdnested initemsByLanguage.{lang}[0].item.auctionId, not at the top level. Added extraction logic to resolve it. - ItemUpdateWorker incomplete —
ItemUpdateWorker::process()was only callingLot::bulkSave()(staging table) without runningInsertLotsBSto process staged data into WP posts andbp_meta_data. Added the InsertLotsBS processing step with autocommit restore. Item updates now flow: stage → InsertLotsBS → WP post + meta → cache clear. - Worker spawn reliability — Changed
SyncQueue::spawnWorker()from non-blocking HTTPS to blocking HTTP loopback (http://127.0.0.1with explicitHostheader, 2s timeout). Fixes nginx 403/404 errors when HTTPS loopback hits the default vhost instead of the site's vhost. - API token constant — Plugin expects
AUCTIONFORGE_API_TOKENinwp-config.php(renamed fromUCO_API_TOKENduring the plugin rename). Documented in readme.
Database
- DB version: 22 → 23
Files Changed
- Modified:
inc/controllers/AuctionsAPI.php,inc/sync/ItemUpdateWorker.php,inc/sync/SyncQueue.php,auctionforge.php,admin/view/sync-status.php,readme.txt
---
[3.0.0] — 2025-03-14
New Feature: Webhook-First Sync Architecture (Sync v3)
Overview: Complete redesign of the BidSpirit data synchronisation pipeline. Replaces the old two-phase polling system (importBidSpirit every hour + importData every minute) with a webhook-driven job queue that processes data in near real-time.
Architecture
- 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: webhook → queue → background worker → WordPress posts. - Dual-write mode — During transition, webhooks enqueue jobs AND still run the legacy handlers. Once verified, legacy handlers can be removed cleanly.
- Job deduplication — Prevents duplicate work by checking for existing pending/processing jobs with the same auction_id + job_type.
New Components
- Job Queue System (
inc/sync/SyncQueue.php) — Priority-based FIFO queue with atomic job claiming, status tracking (pending/processing/completed/failed/skipped), worker PID tracking, and automatic stuck job recovery. - Sync Logger (
inc/sync/SyncLogger.php) — Real-time log table for admin console polling with level filtering (info/success/warning/error) and incremental cursor-based retrieval. - Catalog Sync Worker (
inc/sync/CatalogSyncWorker.php) — Processes catalog_sync, full_sync, and day_ended jobs by reusing existingLotList::singleRun()logic. - Item Update Worker (
inc/sync/ItemUpdateWorker.php) — Processes individual item_update jobs with the same logic as the webhookitemsUpdatedhandler. - Background Worker (
crontasks/syncWorker.php) — Async CLI process spawned by webhooks viaexec()or by the safety cron. Claims and processes queued jobs with a configurable timeout (default 240s). - Safety Net (
crontasks/syncSafety.php) — Hourly cron that resets stuck jobs (>10min), spawns workers for pending jobs, runs a 24-hour health check (auto-enqueues full sync if no webhooks received), and purges old data.
Admin UI
- Queue Status Dashboard — New card on Sync Status page showing pending/processing/completed/failed/skipped counts, recent jobs table with real-time refresh, worker status badge, and action buttons:
- Full Sync — Enqueues catalog sync for all active auctions
- Sync Selected — Enqueue a single auction from dropdown
- Spawn Worker — Manually trigger a background worker process
- Live Console — Dark-themed terminal console on the Sync Status page. Polls
af_sync_logevery 1.5s showing timestamped, color-coded log entries from webhooks, workers, queue operations, and the safety cron. Supports pause, clear, and auto-scroll.
Cron Changes
- Removed
importData(ran every minute — ~1,440 PHP executions/day) - Removed
importBidSpirit(ran hourly — ~24 PHP executions/day) - Added
syncSafety(runs hourly at :10 — 24 PHP executions/day) - Net effect: ~62 PHP executions/hour → 1 PHP execution/hour
- WP-Cron safety hook (
auctionforge_sync_safety) — Always-active hourly event, independent of external cron - setup.sh v3 — Updated task definitions, new
migratecommand for interactive v2→v3 transition
Database
- New table:
af_sync_queue— Job queue with status, priority, source, attempts, worker PID, timing columns - New table:
af_sync_log— Real-time log entries with context, level, auction_id, job_id - DB version: 20 → 22
Constants Added
| Constant | Default | Description |
|---|---|---|
|
AUCTIONFORGE_SYNC_WORKER_TIMEOUT| 240 | Worker process timeout in seconds ||
AUCTIONFORGE_SYNC_STALE_JOB| 600 | Seconds before a processing job is considered stuck ||
AUCTIONFORGE_SYNC_HEALTH_CHECK| 86400 | Seconds without webhook before triggering full sync ||
AUCTIONFORGE_SYNC_LOG_RETENTION| 7 | Days to keep log entries ||
AUCTIONFORGE_SYNC_QUEUE_RETENTION| 30 | Days to keep completed queue jobs ||
AUCTIONFORGE_CURL_TIMEOUT| 30 | BidSpirit API cURL timeout in seconds ||
AUCTIONFORGE_PHP_BINARY| /www/server/php/83/bin/php | PHP CLI binary path for spawning workers |AJAX Handlers Added
auctionforge_sync_log_poll— Incremental log polling for live consoleauctionforge_sync_queue_status— Queue counts + recent jobs for dashboardauctionforge_sync_enqueue— Admin-triggered sync actions (full_sync, sync_auction, spawn_worker)
Fixes
- cURL timeout — BidSpiritRequest now enforces a 30-second timeout (was unlimited/0), preventing hung connections from blocking the sync pipeline.
Files Changed
- Modified:
auctionforge.php,inc/coreIncludes.php,inc/controllers/AuctionsAPI.php,inc/BidSpiritRequest.php,admin/view/sync-status.php,crontasks/setup.sh - Created:
inc/sync/SyncQueue.php,inc/sync/SyncLogger.php,inc/sync/CatalogSyncWorker.php,inc/sync/ItemUpdateWorker.php,crontasks/syncWorker.php,crontasks/syncSafety.php
---
[2.7.3.0]
Fixes
- Various stability improvements and bug fixes.
[2.7.1.2]
Fixes
- Added missing
vatAndCommission()function inloadBid()— the sales tax display on single lot pages was never being rendered because the code to callloadTemplateforvat-and-commission-templatewas missing fromapp.js.
[2.7.1.1]
Fixes
- 2 decimal places now only appear in the bid modal (Your max bid, Total Price) via
showDecimalsflag. 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.
[2.7.0.9]
Fixes
- Fixed fatal error during plugin install/upgrade:
class-stats-database.phprequire failure.
[2.7.0.0]
New Features: Advanced Lot Analytics
- Conversion Tracking, Peak Viewing Times, Pre-Sale vs Live Comparison, Category Performance, Share Analytics, Search → View Funnel, Click-Through Tracking, CSV Export, Hot Lot Badge.
- New DB table:
af_lot_shares. New columns onaf_lot_analytics. DB version bumped to 20.
[2.6.0.0]
New Feature: Lot Analytics
- Comprehensive lot view and favorite tracking system with admin dashboard.
[2.5.0.0]
New Features
- Site Statistics System — Full website analytics built into the plugin admin.
- Recently Viewed Items — Profile page tab showing last 20 viewed lots per user.
- CATALOG_PUBLISHED webhook now triggers catalog sync — Previously only sent push notifications without syncing lots. When the earlier AUCTION_CATALOG_UPDATED fired before the catalog was ready on BidSpirit, lots were never imported. CATALOG_PUBLISHED now calls
-
v3.2.5 Stable Mar 19, 2026Download v3.2.5📦 5.07 MB⚙️ WP 5.2+🔧 PHP 7.2+✓ Tested 6.4
[3.2.5] — 2026-03-19
Sync Reliability & Stuck Lot Prevention
Fixes
- CATALOG_PUBLISHED webhook now triggers catalog sync — Previously only sent push notifications without syncing lots. When the earlier AUCTION_CATALOG_UPDATED fired before the catalog was ready on BidSpirit, lots were never imported. CATALOG_PUBLISHED now calls
auctionCatalogUpdated()to trigger a full catalog sync when the catalog is actually available. - 0-lot API results now fail instead of silently succeeding — When BidSpirit API returns 0 lots (catalog not yet ready), the sync job now fails with an explicit error message, allowing the next webhook to create a fresh retry job.
- Expanded CDN allowlist in pre_http_request filter — The HTTP filter during bulk post insertion now allows all
*.bidspirit.comsubdomains and BidSpirit image CDNs (fastly.net,cloudfront.net). Previously onlybidspirit.comandwww.bidspirit.comwere allowed, blocking image downloads during sync and causing worker hangs. - InsertLotsBS timeout guard — Stage 5 (InsertLotsBS processing loop) now has a 180-second timeout and logs progress every 2 batches. Prevents indefinite hangs that previously required manual force-kill.
- fixResult() no longer marks lots as done when postId=0 — When
lotProcessing()fails to create a WP post, the staging row now keepssyncFinished=0so the lot is retried on the next sync pass, instead of being permanently marked as complete with no actual post. - lotProcessing() logs error on missing auction term — Previously returned 0 silently when
Auction::findAuctionById()failed. Now logs an explicit error that feeds intofixResult()to keep the lot retryable. - Hourly orphan detection in safety cron — New step in
syncSafety.phpdetects lot posts that exist inbp_meta_databut are missing their auction taxonomy assignment (caused by workers killed mid-batch) and auto-repairs them withwp_set_object_terms().
Files Changed
- Modified:
inc/controllers/AuctionsAPI.php,inc/sync/CatalogSyncWorker.php,inc/abs/InsertLotsAbstract.php,inc/import/InsertLotsBS.php,crontasks/syncSafety.php
---
- CATALOG_PUBLISHED webhook now triggers catalog sync — Previously only sent push notifications without syncing lots. When the earlier AUCTION_CATALOG_UPDATED fired before the catalog was ready on BidSpirit, lots were never imported. CATALOG_PUBLISHED now calls
-
v3.2.4.1 Stable Mar 19, 2026Download v3.2.4.1📦 4.84 MB⚙️ WP 5.2+🔧 PHP 7.2+✓ Tested 6.4
AuctionForge Changelog
All notable changes to the AuctionForge plugin are documented in this file.
---
[3.2.4] — 2026-03-18
Sync Worker Hang Fix
Fixes
- Sync workers hanging at InsertLotsBS stage — Third-party plugins (Smush Pro, SmartCrawl SEO, WPMU DEV Updates) hook into
wp_insert_post()and make blocking outbound HTTPS calls for every lot processed. With 489+ lots per auction, this caused workers to hang indefinitely on socket reads to WPMU DEV servers (32.193.94.25,32.193.93.106). AddedWP_IMPORTINGconstant at the REST worker entry point and apre_http_requestfilter inCatalogSyncWorkerthat blocks all non-essential external HTTP during the batch post-insertion phase. Loopback (127.0.0.1,localhost) and BidSpirit API calls remain allowed. - Stuck staging rows after force-kill — When workers were force-killed mid-sync, staging rows in
import_historywere left withsyncstart=1and never unblocked. Subsequent sync runs could not see these rows (filtered out byLot::getRawLots()), causing the InsertLotsBS loop to exit immediately with 0 posts processed. Combined with job deduplication (SyncQueue::enqueue()skips if aprocessingjob exists), this created a deadlock where no new sync could proceed.
Files Changed
- Modified:
auctionforge.php,inc/sync/CatalogSyncWorker.php
---
[3.2.2] — 2026-03-17
Full Sync Auction Discovery Fix
Fixes
- Full Sync finds no auctions on fresh sites — The v3
full_syncaction only queried the WordPress database for existing auction terms, but on a freshly deployed site the database has zero auctions. AddedAuctionList::init()discovery step before querying the DB, so Full Sync now fetches all auctions from the BidSpirit API and creates taxonomy terms first, then enqueues catalog sync jobs for each.
Files Changed
- Modified:
auctionforge.php
---
[3.2.0] — 2026-03-14
Webhook Pipeline Fixes, Archive Sync & Admin UI Overhaul
New Features
- Archive Sync — New "Archive Sync" button on Sync Status admin page. Enqueues catalog sync jobs for all ARCHIVED/ENDED auctions. Past auctions now appear in the auction dropdown with an optgroup separator and state label.
- Sync Tasks v3 — Replaced old v2 task cards (importData, importBidSpirit, lotBidSpiritOld) with v3 queue-based tasks. "Sync Active Auctions" and "Sync Archived Auctions" now enqueue jobs via the queue system. Maintenance tasks (Clean Draft/Trash Lots, Clean Orphaned Meta) remain as direct-execution tasks.
- How It Works guide rewritten — Complete rewrite of the admin guide for v3 architecture. Documents webhook-first flow, all 5 job types, queue system mechanics, cron setup (external + WP-Cron), configuration constants, and troubleshooting.
Fixes
- Dual-write removed — Removed legacy handlers from
auctionCatalogUpdated(),auctionDayEnded(), anditemsUpdated()webhook methods. The old handlers were racing with the v3 worker, creating orphaned staging rows inimport_historythat were never processed. All three methods now exclusively use the v3 enqueue → spawn path. - ITEMS_UPDATED webhook — Fixed
itemsUpdated()failing to enqueue jobs. TheITEMS_UPDATEDpayload hasauctionIdnested initemsByLanguage.{lang}[0].item.auctionId, not at the top level. Added extraction logic to resolve it. - ItemUpdateWorker incomplete —
ItemUpdateWorker::process()was only callingLot::bulkSave()(staging table) without runningInsertLotsBSto process staged data into WP posts andbp_meta_data. Added the InsertLotsBS processing step with autocommit restore. Item updates now flow: stage → InsertLotsBS → WP post + meta → cache clear. - Worker spawn reliability — Changed
SyncQueue::spawnWorker()from non-blocking HTTPS to blocking HTTP loopback (http://127.0.0.1with explicitHostheader, 2s timeout). Fixes nginx 403/404 errors when HTTPS loopback hits the default vhost instead of the site's vhost. - API token constant — Plugin expects
AUCTIONFORGE_API_TOKENinwp-config.php(renamed fromUCO_API_TOKENduring the plugin rename). Documented in readme.
Database
- DB version: 22 → 23
Files Changed
- Modified:
inc/controllers/AuctionsAPI.php,inc/sync/ItemUpdateWorker.php,inc/sync/SyncQueue.php,auctionforge.php,admin/view/sync-status.php,readme.txt
---
[3.0.0] — 2025-03-14
New Feature: Webhook-First Sync Architecture (Sync v3)
Overview: Complete redesign of the BidSpirit data synchronisation pipeline. Replaces the old two-phase polling system (importBidSpirit every hour + importData every minute) with a webhook-driven job queue that processes data in near real-time.
Architecture
- 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: webhook → queue → background worker → WordPress posts. - Dual-write mode — During transition, webhooks enqueue jobs AND still run the legacy handlers. Once verified, legacy handlers can be removed cleanly.
- Job deduplication — Prevents duplicate work by checking for existing pending/processing jobs with the same auction_id + job_type.
New Components
- Job Queue System (
inc/sync/SyncQueue.php) — Priority-based FIFO queue with atomic job claiming, status tracking (pending/processing/completed/failed/skipped), worker PID tracking, and automatic stuck job recovery. - Sync Logger (
inc/sync/SyncLogger.php) — Real-time log table for admin console polling with level filtering (info/success/warning/error) and incremental cursor-based retrieval. - Catalog Sync Worker (
inc/sync/CatalogSyncWorker.php) — Processes catalog_sync, full_sync, and day_ended jobs by reusing existingLotList::singleRun()logic. - Item Update Worker (
inc/sync/ItemUpdateWorker.php) — Processes individual item_update jobs with the same logic as the webhookitemsUpdatedhandler. - Background Worker (
crontasks/syncWorker.php) — Async CLI process spawned by webhooks viaexec()or by the safety cron. Claims and processes queued jobs with a configurable timeout (default 240s). - Safety Net (
crontasks/syncSafety.php) — Hourly cron that resets stuck jobs (>10min), spawns workers for pending jobs, runs a 24-hour health check (auto-enqueues full sync if no webhooks received), and purges old data.
Admin UI
- Queue Status Dashboard — New card on Sync Status page showing pending/processing/completed/failed/skipped counts, recent jobs table with real-time refresh, worker status badge, and action buttons:
- Full Sync — Enqueues catalog sync for all active auctions
- Sync Selected — Enqueue a single auction from dropdown
- Spawn Worker — Manually trigger a background worker process
- Live Console — Dark-themed terminal console on the Sync Status page. Polls
af_sync_logevery 1.5s showing timestamped, color-coded log entries from webhooks, workers, queue operations, and the safety cron. Supports pause, clear, and auto-scroll.
Cron Changes
- Removed
importData(ran every minute — ~1,440 PHP executions/day) - Removed
importBidSpirit(ran hourly — ~24 PHP executions/day) - Added
syncSafety(runs hourly at :10 — 24 PHP executions/day) - Net effect: ~62 PHP executions/hour → 1 PHP execution/hour
- WP-Cron safety hook (
auctionforge_sync_safety) — Always-active hourly event, independent of external cron - setup.sh v3 — Updated task definitions, new
migratecommand for interactive v2→v3 transition
Database
- New table:
af_sync_queue— Job queue with status, priority, source, attempts, worker PID, timing columns - New table:
af_sync_log— Real-time log entries with context, level, auction_id, job_id - DB version: 20 → 22
Constants Added
| Constant | Default | Description |
|---|---|---|
|
AUCTIONFORGE_SYNC_WORKER_TIMEOUT| 240 | Worker process timeout in seconds ||
AUCTIONFORGE_SYNC_STALE_JOB| 600 | Seconds before a processing job is considered stuck ||
AUCTIONFORGE_SYNC_HEALTH_CHECK| 86400 | Seconds without webhook before triggering full sync ||
AUCTIONFORGE_SYNC_LOG_RETENTION| 7 | Days to keep log entries ||
AUCTIONFORGE_SYNC_QUEUE_RETENTION| 30 | Days to keep completed queue jobs ||
AUCTIONFORGE_CURL_TIMEOUT| 30 | BidSpirit API cURL timeout in seconds ||
AUCTIONFORGE_PHP_BINARY| /www/server/php/83/bin/php | PHP CLI binary path for spawning workers |AJAX Handlers Added
auctionforge_sync_log_poll— Incremental log polling for live consoleauctionforge_sync_queue_status— Queue counts + recent jobs for dashboardauctionforge_sync_enqueue— Admin-triggered sync actions (full_sync, sync_auction, spawn_worker)
Fixes
- cURL timeout — BidSpiritRequest now enforces a 30-second timeout (was unlimited/0), preventing hung connections from blocking the sync pipeline.
Files Changed
- Modified:
auctionforge.php,inc/coreIncludes.php,inc/controllers/AuctionsAPI.php,inc/BidSpiritRequest.php,admin/view/sync-status.php,crontasks/setup.sh - Created:
inc/sync/SyncQueue.php,inc/sync/SyncLogger.php,inc/sync/CatalogSyncWorker.php,inc/sync/ItemUpdateWorker.php,crontasks/syncWorker.php,crontasks/syncSafety.php
---
[2.7.3.0]
Fixes
- Various stability improvements and bug fixes.
[2.7.1.2]
Fixes
- Added missing
vatAndCommission()function inloadBid()— the sales tax display on single lot pages was never being rendered because the code to callloadTemplateforvat-and-commission-templatewas missing fromapp.js.
[2.7.1.1]
Fixes
- 2 decimal places now only appear in the bid modal (Your max bid, Total Price) via
showDecimalsflag. 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.
[2.7.0.9]
Fixes
- Fixed fatal error during plugin install/upgrade:
class-stats-database.phprequire failure.
[2.7.0.0]
New Features: Advanced Lot Analytics
- Conversion Tracking, Peak Viewing Times, Pre-Sale vs Live Comparison, Category Performance, Share Analytics, Search → View Funnel, Click-Through Tracking, CSV Export, Hot Lot Badge.
- New DB table:
af_lot_shares. New columns onaf_lot_analytics. DB version bumped to 20.
[2.6.0.0]
New Feature: Lot Analytics
- Comprehensive lot view and favorite tracking system with admin dashboard.
[2.5.0.0]
New Features
- Site Statistics System — Full website analytics built into the plugin admin.
- Recently Viewed Items — Profile page tab showing last 20 viewed lots per user.
- Sync workers hanging at InsertLotsBS stage — Third-party plugins (Smush Pro, SmartCrawl SEO, WPMU DEV Updates) hook into
-
v3.2.4 Stable Mar 18, 2026Download v3.2.4📦 5.07 MB⚙️ WP 5.2+🔧 PHP 7.2+✓ Tested 6.4
[3.2.4] — 2026-03-18
Sync Worker Hang Fix
Fixes
- Sync workers hanging at InsertLotsBS stage — Third-party plugins (Smush Pro, SmartCrawl SEO, WPMU DEV Updates) hook into
wp_insert_post()and make blocking outbound HTTPS calls for every lot processed. With 489+ lots per auction, this caused workers to hang indefinitely on socket reads to WPMU DEV servers (32.193.94.25,32.193.93.106). AddedWP_IMPORTINGconstant at the REST worker entry point and apre_http_requestfilter inCatalogSyncWorkerthat blocks all non-essential external HTTP during the batch post-insertion phase. Loopback (127.0.0.1,localhost) and BidSpirit API calls remain allowed. - Stuck staging rows after force-kill — When workers were force-killed mid-sync, staging rows in
import_historywere left withsyncstart=1and never unblocked. Subsequent sync runs could not see these rows (filtered out byLot::getRawLots()), causing the InsertLotsBS loop to exit immediately with 0 posts processed. Combined with job deduplication (SyncQueue::enqueue()skips if aprocessingjob exists), this created a deadlock where no new sync could proceed.
Files Changed
- Modified:
auctionforge.php,inc/sync/CatalogSyncWorker.php
---
- Sync workers hanging at InsertLotsBS stage — Third-party plugins (Smush Pro, SmartCrawl SEO, WPMU DEV Updates) hook into
-
v3.2.3.1 Stable Mar 18, 2026Download v3.2.3.1📦 4.85 MB⚙️ WP 5.2+🔧 PHP 7.2+✓ Tested 6.4
AuctionForge Changelog
All notable changes to the AuctionForge plugin are documented in this file.
---
[3.2.2] — 2026-03-17
Full Sync Auction Discovery Fix
Fixes
- Full Sync finds no auctions on fresh sites — The v3
full_syncaction only queried the WordPress database for existing auction terms, but on a freshly deployed site the database has zero auctions. AddedAuctionList::init()discovery step before querying the DB, so Full Sync now fetches all auctions from the BidSpirit API and creates taxonomy terms first, then enqueues catalog sync jobs for each.
Files Changed
- Modified:
auctionforge.php
---
[3.2.0] — 2026-03-14
Webhook Pipeline Fixes, Archive Sync & Admin UI Overhaul
New Features
- Archive Sync — New "Archive Sync" button on Sync Status admin page. Enqueues catalog sync jobs for all ARCHIVED/ENDED auctions. Past auctions now appear in the auction dropdown with an optgroup separator and state label.
- Sync Tasks v3 — Replaced old v2 task cards (importData, importBidSpirit, lotBidSpiritOld) with v3 queue-based tasks. "Sync Active Auctions" and "Sync Archived Auctions" now enqueue jobs via the queue system. Maintenance tasks (Clean Draft/Trash Lots, Clean Orphaned Meta) remain as direct-execution tasks.
- How It Works guide rewritten — Complete rewrite of the admin guide for v3 architecture. Documents webhook-first flow, all 5 job types, queue system mechanics, cron setup (external + WP-Cron), configuration constants, and troubleshooting.
Fixes
- Dual-write removed — Removed legacy handlers from
auctionCatalogUpdated(),auctionDayEnded(), anditemsUpdated()webhook methods. The old handlers were racing with the v3 worker, creating orphaned staging rows inimport_historythat were never processed. All three methods now exclusively use the v3 enqueue → spawn path. - ITEMS_UPDATED webhook — Fixed
itemsUpdated()failing to enqueue jobs. TheITEMS_UPDATEDpayload hasauctionIdnested initemsByLanguage.{lang}[0].item.auctionId, not at the top level. Added extraction logic to resolve it. - ItemUpdateWorker incomplete —
ItemUpdateWorker::process()was only callingLot::bulkSave()(staging table) without runningInsertLotsBSto process staged data into WP posts andbp_meta_data. Added the InsertLotsBS processing step with autocommit restore. Item updates now flow: stage → InsertLotsBS → WP post + meta → cache clear. - Worker spawn reliability — Changed
SyncQueue::spawnWorker()from non-blocking HTTPS to blocking HTTP loopback (http://127.0.0.1with explicitHostheader, 2s timeout). Fixes nginx 403/404 errors when HTTPS loopback hits the default vhost instead of the site's vhost. - API token constant — Plugin expects
AUCTIONFORGE_API_TOKENinwp-config.php(renamed fromUCO_API_TOKENduring the plugin rename). Documented in readme.
Database
- DB version: 22 → 23
Files Changed
- Modified:
inc/controllers/AuctionsAPI.php,inc/sync/ItemUpdateWorker.php,inc/sync/SyncQueue.php,auctionforge.php,admin/view/sync-status.php,readme.txt
---
[3.0.0] — 2025-03-14
New Feature: Webhook-First Sync Architecture (Sync v3)
Overview: Complete redesign of the BidSpirit data synchronisation pipeline. Replaces the old two-phase polling system (importBidSpirit every hour + importData every minute) with a webhook-driven job queue that processes data in near real-time.
Architecture
- 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: webhook → queue → background worker → WordPress posts. - Dual-write mode — During transition, webhooks enqueue jobs AND still run the legacy handlers. Once verified, legacy handlers can be removed cleanly.
- Job deduplication — Prevents duplicate work by checking for existing pending/processing jobs with the same auction_id + job_type.
New Components
- Job Queue System (
inc/sync/SyncQueue.php) — Priority-based FIFO queue with atomic job claiming, status tracking (pending/processing/completed/failed/skipped), worker PID tracking, and automatic stuck job recovery. - Sync Logger (
inc/sync/SyncLogger.php) — Real-time log table for admin console polling with level filtering (info/success/warning/error) and incremental cursor-based retrieval. - Catalog Sync Worker (
inc/sync/CatalogSyncWorker.php) — Processes catalog_sync, full_sync, and day_ended jobs by reusing existingLotList::singleRun()logic. - Item Update Worker (
inc/sync/ItemUpdateWorker.php) — Processes individual item_update jobs with the same logic as the webhookitemsUpdatedhandler. - Background Worker (
crontasks/syncWorker.php) — Async CLI process spawned by webhooks viaexec()or by the safety cron. Claims and processes queued jobs with a configurable timeout (default 240s). - Safety Net (
crontasks/syncSafety.php) — Hourly cron that resets stuck jobs (>10min), spawns workers for pending jobs, runs a 24-hour health check (auto-enqueues full sync if no webhooks received), and purges old data.
Admin UI
- Queue Status Dashboard — New card on Sync Status page showing pending/processing/completed/failed/skipped counts, recent jobs table with real-time refresh, worker status badge, and action buttons:
- Full Sync — Enqueues catalog sync for all active auctions
- Sync Selected — Enqueue a single auction from dropdown
- Spawn Worker — Manually trigger a background worker process
- Live Console — Dark-themed terminal console on the Sync Status page. Polls
af_sync_logevery 1.5s showing timestamped, color-coded log entries from webhooks, workers, queue operations, and the safety cron. Supports pause, clear, and auto-scroll.
Cron Changes
- Removed
importData(ran every minute — ~1,440 PHP executions/day) - Removed
importBidSpirit(ran hourly — ~24 PHP executions/day) - Added
syncSafety(runs hourly at :10 — 24 PHP executions/day) - Net effect: ~62 PHP executions/hour → 1 PHP execution/hour
- WP-Cron safety hook (
auctionforge_sync_safety) — Always-active hourly event, independent of external cron - setup.sh v3 — Updated task definitions, new
migratecommand for interactive v2→v3 transition
Database
- New table:
af_sync_queue— Job queue with status, priority, source, attempts, worker PID, timing columns - New table:
af_sync_log— Real-time log entries with context, level, auction_id, job_id - DB version: 20 → 22
Constants Added
| Constant | Default | Description |
|---|---|---|
|
AUCTIONFORGE_SYNC_WORKER_TIMEOUT| 240 | Worker process timeout in seconds ||
AUCTIONFORGE_SYNC_STALE_JOB| 600 | Seconds before a processing job is considered stuck ||
AUCTIONFORGE_SYNC_HEALTH_CHECK| 86400 | Seconds without webhook before triggering full sync ||
AUCTIONFORGE_SYNC_LOG_RETENTION| 7 | Days to keep log entries ||
AUCTIONFORGE_SYNC_QUEUE_RETENTION| 30 | Days to keep completed queue jobs ||
AUCTIONFORGE_CURL_TIMEOUT| 30 | BidSpirit API cURL timeout in seconds ||
AUCTIONFORGE_PHP_BINARY| /www/server/php/83/bin/php | PHP CLI binary path for spawning workers |AJAX Handlers Added
auctionforge_sync_log_poll— Incremental log polling for live consoleauctionforge_sync_queue_status— Queue counts + recent jobs for dashboardauctionforge_sync_enqueue— Admin-triggered sync actions (full_sync, sync_auction, spawn_worker)
Fixes
- cURL timeout — BidSpiritRequest now enforces a 30-second timeout (was unlimited/0), preventing hung connections from blocking the sync pipeline.
Files Changed
- Modified:
auctionforge.php,inc/coreIncludes.php,inc/controllers/AuctionsAPI.php,inc/BidSpiritRequest.php,admin/view/sync-status.php,crontasks/setup.sh - Created:
inc/sync/SyncQueue.php,inc/sync/SyncLogger.php,inc/sync/CatalogSyncWorker.php,inc/sync/ItemUpdateWorker.php,crontasks/syncWorker.php,crontasks/syncSafety.php
---
[2.7.3.0]
Fixes
- Various stability improvements and bug fixes.
[2.7.1.2]
Fixes
- Added missing
vatAndCommission()function inloadBid()— the sales tax display on single lot pages was never being rendered because the code to callloadTemplateforvat-and-commission-templatewas missing fromapp.js.
[2.7.1.1]
Fixes
- 2 decimal places now only appear in the bid modal (Your max bid, Total Price) via
showDecimalsflag. 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.
[2.7.0.9]
Fixes
- Fixed fatal error during plugin install/upgrade:
class-stats-database.phprequire failure.
[2.7.0.0]
New Features: Advanced Lot Analytics
- Conversion Tracking, Peak Viewing Times, Pre-Sale vs Live Comparison, Category Performance, Share Analytics, Search → View Funnel, Click-Through Tracking, CSV Export, Hot Lot Badge.
- New DB table:
af_lot_shares. New columns onaf_lot_analytics. DB version bumped to 20.
[2.6.0.0]
New Feature: Lot Analytics
- Comprehensive lot view and favorite tracking system with admin dashboard.
[2.5.0.0]
New Features
- Site Statistics System — Full website analytics built into the plugin admin.
- Recently Viewed Items — Profile page tab showing last 20 viewed lots per user.
- Full Sync finds no auctions on fresh sites — The v3
-
v3.2.2 Stable Mar 17, 2026Download v3.2.2📦 5.07 MB⚙️ WP 5.2+🔧 PHP 7.2+✓ Tested 6.4
[3.2.2] — 2026-03-17
Full Sync Auction Discovery Fix
Fixes
- Full Sync finds no auctions on fresh sites — The v3
full_syncaction only queried the WordPress database for existing auction terms, but on a freshly deployed site the database has zero auctions. AddedAuctionList::init()discovery step before querying the DB, so Full Sync now fetches all auctions from the BidSpirit API and creates taxonomy terms first, then enqueues catalog sync jobs for each.
Files Changed
- Modified:
auctionforge.php
---
- Full Sync finds no auctions on fresh sites — The v3
-
v3.2.1 Stable Mar 16, 2026Download v3.2.1📦 5.07 MB⚙️ WP 5.2+🔧 PHP 7.2+✓ Tested 6.4
[3.2.1] — 2026-03-16
Sync Worker Fix & Lot Analytics Default
Fixes
- Critical: Autocommit rollback bug —
InsertLotsBS::init()setsautocommit=0(whenAUTO_COMMIT_DISABLEDis enabled) but never restores it. After the InsertLotsBS processing loop, all subsequent DB writes —SyncLogger::log(),SyncQueue::complete()— were in an uncommitted transaction that got silently rolled back when the PHP-FPM process exited. This caused sync jobs to appear permanently stuck in "processing" status despite actually completing. Fixed by addingCOMMIT; SET autocommit = 1;after the InsertLotsBS loop in bothCatalogSyncWorker::process()andprocessDayEnded(). - Lot analytics enabled by default — Changed the fallback default for
enable_lot_analyticsfrom'off'to'on'across all code paths (settings, templates, AJAX handlers, shortcodes, stats tracker). New installs now have lot analytics active without requiring manual configuration.
Files Changed
- Modified:
inc/sync/CatalogSyncWorker.php,inc/import/InsertLotsBS.php,inc/controllers/Settings.php,inc/controllers/BidspiritViews.php,templates/single-lot.php,admin/view/stats/dashboard.php,inc/stats/class-stats-ajax.php,inc/stats/class-stats-tracker.php,inc/shortcodes/PopularLots.php,ajax/LotAnalytics.php
---
- Critical: Autocommit rollback bug —
-
v3.2.0 Stable Mar 14, 2026Download v3.2.0📦 5.07 MB⚙️ WP 5.2+🔧 PHP 7.2+✓ Tested 6.4
[3.2.0] — 2026-03-14
Webhook Pipeline Fixes, Archive Sync & Admin UI Overhaul
New Features
- Archive Sync — New "Archive Sync" button on Sync Status admin page. Enqueues catalog sync jobs for all ARCHIVED/ENDED auctions. Past auctions now appear in the auction dropdown with an optgroup separator and state label.
- Sync Tasks v3 — Replaced old v2 task cards (importData, importBidSpirit, lotBidSpiritOld) with v3 queue-based tasks. "Sync Active Auctions" and "Sync Archived Auctions" now enqueue jobs via the queue system. Maintenance tasks (Clean Draft/Trash Lots, Clean Orphaned Meta) remain as direct-execution tasks.
- How It Works guide rewritten — Complete rewrite of the admin guide for v3 architecture. Documents webhook-first flow, all 5 job types, queue system mechanics, cron setup (external + WP-Cron), configuration constants, and troubleshooting.
Fixes
- Dual-write removed — Removed legacy handlers from
auctionCatalogUpdated(),auctionDayEnded(), anditemsUpdated()webhook methods. The old handlers were racing with the v3 worker, creating orphaned staging rows inimport_historythat were never processed. All three methods now exclusively use the v3 enqueue → spawn path. - ITEMS_UPDATED webhook — Fixed
itemsUpdated()failing to enqueue jobs. TheITEMS_UPDATEDpayload hasauctionIdnested initemsByLanguage.{lang}[0].item.auctionId, not at the top level. Added extraction logic to resolve it. - ItemUpdateWorker incomplete —
ItemUpdateWorker::process()was only callingLot::bulkSave()(staging table) without runningInsertLotsBSto process staged data into WP posts andbp_meta_data. Added the InsertLotsBS processing step with autocommit restore. Item updates now flow: stage → InsertLotsBS → WP post + meta → cache clear. - Worker spawn reliability — Changed
SyncQueue::spawnWorker()from non-blocking HTTPS to blocking HTTP loopback (http://127.0.0.1with explicitHostheader, 2s timeout). Fixes nginx 403/404 errors when HTTPS loopback hits the default vhost instead of the site's vhost. - API token constant — Plugin expects
AUCTIONFORGE_API_TOKENinwp-config.php(renamed fromUCO_API_TOKENduring the plugin rename). Documented in readme.
Database
- DB version: 22 → 23
Files Changed
- Modified:
inc/controllers/AuctionsAPI.php,inc/sync/ItemUpdateWorker.php,inc/sync/SyncQueue.php,auctionforge.php,admin/view/sync-status.php,readme.txt
---
-
v3.1.0 Stable Mar 14, 2026Download v3.1.0📦 5.07 MB⚙️ WP 5.2+🔧 PHP 7.2+✓ Tested 6.4
[3.1.0] — 2026-03-14
Webhook Pipeline Fixes & Archive Sync
New Features
- Archive Sync — New "Archive Sync" button on Sync Status admin page. Enqueues catalog sync jobs for all ARCHIVED/ENDED auctions. Past auctions now appear in the auction dropdown with an optgroup separator and state label.
Fixes
- Dual-write removed — Removed legacy handlers from
auctionCatalogUpdated(),auctionDayEnded(), anditemsUpdated()webhook methods. The old handlers were racing with the v3 worker, creating orphaned staging rows inimport_historythat were never processed. All three methods now exclusively use the v3 enqueue → spawn path. - ITEMS_UPDATED webhook — Fixed
itemsUpdated()failing to enqueue jobs. TheITEMS_UPDATEDpayload hasauctionIdnested initemsByLanguage.{lang}[0].item.auctionId, not at the top level. Added extraction logic to resolve it. - ItemUpdateWorker incomplete —
ItemUpdateWorker::process()was only callingLot::bulkSave()(staging table) without runningInsertLotsBSto process staged data into WP posts andbp_meta_data. Added the InsertLotsBS processing step with autocommit restore. Item updates now flow: stage → InsertLotsBS → WP post + meta → cache clear. - Worker spawn reliability — Changed
SyncQueue::spawnWorker()from non-blocking HTTPS to blocking HTTP loopback (http://127.0.0.1with explicitHostheader, 2s timeout). Fixes nginx 403/404 errors when HTTPS loopback hits the default vhost instead of the site's vhost. - API token constant — Plugin expects
AUCTIONFORGE_API_TOKENinwp-config.php(renamed fromUCO_API_TOKENduring the plugin rename). Documented in readme.
Files Changed
- Modified:
inc/controllers/AuctionsAPI.php,inc/sync/ItemUpdateWorker.php,inc/sync/SyncQueue.php,auctionforge.php,admin/view/sync-status.php
---
-
v2.7.3.0 Stable Mar 14, 2026Download v2.7.3.0📦 4.82 MB⚙️ WP 5.2+🔧 PHP 7.2+✓ Tested 6.4
2.7.1.2
Fixes:
- Added missing
vatAndCommission()function inloadBid()— the sales tax display on single lot pages was never being rendered because the code to callloadTemplateforvat-and-commission-templatewas missing fromapp.js. Also added missingsetAuctionItemInfo()call.
2.7.1.1
Fixes:
- 2 decimal places now only appear in the bid modal (Your max bid, Total Price) via
showDecimalsflag. 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-fieldpopulation inauctionInfoInit()from upstream reference.
2.7.0.9
Fixes:
- Fixed fatal error during plugin install/upgrade:
class-stats-database.phprequire failure. Addedfile_existsguard inAF_Stats_Init::activate()and plugin-specific guard inupgrader_process_completehook to prevent running upgrade logic for unrelated plugin updates.
2.7.0.8
Fixes:
- Synced
formattedPrice()across bothapp.jsandapp.min.js— added second currency support, better null/NaN handling, and always 2 decimal places on all prices. Fixes sites where minification plugins may loadapp.min.jsinstead ofapp.js.
2.7.0.7
Fixes:
- All prices now display with 2 decimal places (e.g. $10.00 instead of $10) via
formattedPrice()usingtoLocaleStringwithminimumFractionDigits: 2.
2.7.0.6
Fixes:
- Added missing
estimatedPrice,content, andisShoptemplate variables to widget and shortcodelot-content-templatecalls, 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 —
#stripePaymentElementhadhiddenclass that was never removed. Now unhides form on Stripereadyevent and re-hides on modal close.
2.7.0.4
Fixes:
- Fixed
bidspiritApi.getAuctionSettingsData is not a functionerror in getFullPriceInfo — use local auctionSettingsData variable instead of non-existent API method.
2.7.0.3
Fixes:
- Fixed
fullPriceInfo is not definedReferenceError that prevented bid confirmation modal from opening on single lot pages and catalogue pages. - Added missing
getFullPriceInfo(),getCommissonInfoForPrice(), androundToCents()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 definedindisplayBidFormData— removed strayitem: itemfrom house-info-template call where item variable does not exist in scope.
2.5.2.0
Fixes:
- Fixed
item is not definedJavaScript error inauctionIsLive-templateon 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 definedJavaScript 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_loadedfor 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 definedJavaScript error on auction catalog and single lot pages. - Fixed
postAuctionSaleOpened is not definedJavaScript error on auction pages. - Fixed missing
vendor.min.cssandpassword-validation.min.css(404 errors). - Added missing template variables to all
loadTemplatecalls forlot-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.
- Added missing
-
v2.7.2.9 Stable Mar 14, 2026Download v2.7.2.9📦 4.82 MB⚙️ WP 5.2+🔧 PHP 7.2+✓ Tested 6.4
2.7.1.2
Fixes:
- Added missing
vatAndCommission()function inloadBid()— the sales tax display on single lot pages was never being rendered because the code to callloadTemplateforvat-and-commission-templatewas missing fromapp.js. Also added missingsetAuctionItemInfo()call.
2.7.1.1
Fixes:
- 2 decimal places now only appear in the bid modal (Your max bid, Total Price) via
showDecimalsflag. 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-fieldpopulation inauctionInfoInit()from upstream reference.
2.7.0.9
Fixes:
- Fixed fatal error during plugin install/upgrade:
class-stats-database.phprequire failure. Addedfile_existsguard inAF_Stats_Init::activate()and plugin-specific guard inupgrader_process_completehook to prevent running upgrade logic for unrelated plugin updates.
2.7.0.8
Fixes:
- Synced
formattedPrice()across bothapp.jsandapp.min.js— added second currency support, better null/NaN handling, and always 2 decimal places on all prices. Fixes sites where minification plugins may loadapp.min.jsinstead ofapp.js.
2.7.0.7
Fixes:
- All prices now display with 2 decimal places (e.g. $10.00 instead of $10) via
formattedPrice()usingtoLocaleStringwithminimumFractionDigits: 2.
2.7.0.6
Fixes:
- Added missing
estimatedPrice,content, andisShoptemplate variables to widget and shortcodelot-content-templatecalls, 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 —
#stripePaymentElementhadhiddenclass that was never removed. Now unhides form on Stripereadyevent and re-hides on modal close.
2.7.0.4
Fixes:
- Fixed
bidspiritApi.getAuctionSettingsData is not a functionerror in getFullPriceInfo — use local auctionSettingsData variable instead of non-existent API method.
2.7.0.3
Fixes:
- Fixed
fullPriceInfo is not definedReferenceError that prevented bid confirmation modal from opening on single lot pages and catalogue pages. - Added missing
getFullPriceInfo(),getCommissonInfoForPrice(), androundToCents()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 definedindisplayBidFormData— removed strayitem: itemfrom house-info-template call where item variable does not exist in scope.
2.5.2.0
Fixes:
- Fixed
item is not definedJavaScript error inauctionIsLive-templateon 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 definedJavaScript 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_loadedfor 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 definedJavaScript error on auction catalog and single lot pages. - Fixed
postAuctionSaleOpened is not definedJavaScript error on auction pages. - Fixed missing
vendor.min.cssandpassword-validation.min.css(404 errors). - Added missing template variables to all
loadTemplatecalls forlot-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.
- Added missing
-
v2.7.2.7 Stable Mar 13, 2026Download v2.7.2.7📦 4.82 MB⚙️ WP 5.2+🔧 PHP 7.2+✓ Tested 6.4
2.7.1.2
Fixes:
- Added missing
vatAndCommission()function inloadBid()— the sales tax display on single lot pages was never being rendered because the code to callloadTemplateforvat-and-commission-templatewas missing fromapp.js. Also added missingsetAuctionItemInfo()call.
2.7.1.1
Fixes:
- 2 decimal places now only appear in the bid modal (Your max bid, Total Price) via
showDecimalsflag. 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-fieldpopulation inauctionInfoInit()from upstream reference.
2.7.0.9
Fixes:
- Fixed fatal error during plugin install/upgrade:
class-stats-database.phprequire failure. Addedfile_existsguard inAF_Stats_Init::activate()and plugin-specific guard inupgrader_process_completehook to prevent running upgrade logic for unrelated plugin updates.
2.7.0.8
Fixes:
- Synced
formattedPrice()across bothapp.jsandapp.min.js— added second currency support, better null/NaN handling, and always 2 decimal places on all prices. Fixes sites where minification plugins may loadapp.min.jsinstead ofapp.js.
2.7.0.7
Fixes:
- All prices now display with 2 decimal places (e.g. $10.00 instead of $10) via
formattedPrice()usingtoLocaleStringwithminimumFractionDigits: 2.
2.7.0.6
Fixes:
- Added missing
estimatedPrice,content, andisShoptemplate variables to widget and shortcodelot-content-templatecalls, 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 —
#stripePaymentElementhadhiddenclass that was never removed. Now unhides form on Stripereadyevent and re-hides on modal close.
2.7.0.4
Fixes:
- Fixed
bidspiritApi.getAuctionSettingsData is not a functionerror in getFullPriceInfo — use local auctionSettingsData variable instead of non-existent API method.
2.7.0.3
Fixes:
- Fixed
fullPriceInfo is not definedReferenceError that prevented bid confirmation modal from opening on single lot pages and catalogue pages. - Added missing
getFullPriceInfo(),getCommissonInfoForPrice(), androundToCents()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 definedindisplayBidFormData— removed strayitem: itemfrom house-info-template call where item variable does not exist in scope.
2.5.2.0
Fixes:
- Fixed
item is not definedJavaScript error inauctionIsLive-templateon 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 definedJavaScript 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_loadedfor 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 definedJavaScript error on auction catalog and single lot pages. - Fixed
postAuctionSaleOpened is not definedJavaScript error on auction pages. - Fixed missing
vendor.min.cssandpassword-validation.min.css(404 errors). - Added missing template variables to all
loadTemplatecalls forlot-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.
- Added missing
-
v2.7.2.6 Stable Mar 13, 2026Download v2.7.2.6📦 4.82 MB⚙️ WP 5.2+🔧 PHP 7.2+✓ Tested 6.4
2.7.1.2
Fixes:
- Added missing
vatAndCommission()function inloadBid()— the sales tax display on single lot pages was never being rendered because the code to callloadTemplateforvat-and-commission-templatewas missing fromapp.js. Also added missingsetAuctionItemInfo()call.
2.7.1.1
Fixes:
- 2 decimal places now only appear in the bid modal (Your max bid, Total Price) via
showDecimalsflag. 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-fieldpopulation inauctionInfoInit()from upstream reference.
2.7.0.9
Fixes:
- Fixed fatal error during plugin install/upgrade:
class-stats-database.phprequire failure. Addedfile_existsguard inAF_Stats_Init::activate()and plugin-specific guard inupgrader_process_completehook to prevent running upgrade logic for unrelated plugin updates.
2.7.0.8
Fixes:
- Synced
formattedPrice()across bothapp.jsandapp.min.js— added second currency support, better null/NaN handling, and always 2 decimal places on all prices. Fixes sites where minification plugins may loadapp.min.jsinstead ofapp.js.
2.7.0.7
Fixes:
- All prices now display with 2 decimal places (e.g. $10.00 instead of $10) via
formattedPrice()usingtoLocaleStringwithminimumFractionDigits: 2.
2.7.0.6
Fixes:
- Added missing
estimatedPrice,content, andisShoptemplate variables to widget and shortcodelot-content-templatecalls, 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 —
#stripePaymentElementhadhiddenclass that was never removed. Now unhides form on Stripereadyevent and re-hides on modal close.
2.7.0.4
Fixes:
- Fixed
bidspiritApi.getAuctionSettingsData is not a functionerror in getFullPriceInfo — use local auctionSettingsData variable instead of non-existent API method.
2.7.0.3
Fixes:
- Fixed
fullPriceInfo is not definedReferenceError that prevented bid confirmation modal from opening on single lot pages and catalogue pages. - Added missing
getFullPriceInfo(),getCommissonInfoForPrice(), androundToCents()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 definedindisplayBidFormData— removed strayitem: itemfrom house-info-template call where item variable does not exist in scope.
2.5.2.0
Fixes:
- Fixed
item is not definedJavaScript error inauctionIsLive-templateon 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 definedJavaScript 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_loadedfor 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 definedJavaScript error on auction catalog and single lot pages. - Fixed
postAuctionSaleOpened is not definedJavaScript error on auction pages. - Fixed missing
vendor.min.cssandpassword-validation.min.css(404 errors). - Added missing template variables to all
loadTemplatecalls forlot-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.
- Added missing
-
v2.7.2.5 Stable Mar 13, 2026Download v2.7.2.5📦 4.82 MB⚙️ WP 5.2+🔧 PHP 7.2+✓ Tested 6.4
2.7.1.2
Fixes:
- Added missing
vatAndCommission()function inloadBid()— the sales tax display on single lot pages was never being rendered because the code to callloadTemplateforvat-and-commission-templatewas missing fromapp.js. Also added missingsetAuctionItemInfo()call.
2.7.1.1
Fixes:
- 2 decimal places now only appear in the bid modal (Your max bid, Total Price) via
showDecimalsflag. 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-fieldpopulation inauctionInfoInit()from upstream reference.
2.7.0.9
Fixes:
- Fixed fatal error during plugin install/upgrade:
class-stats-database.phprequire failure. Addedfile_existsguard inAF_Stats_Init::activate()and plugin-specific guard inupgrader_process_completehook to prevent running upgrade logic for unrelated plugin updates.
2.7.0.8
Fixes:
- Synced
formattedPrice()across bothapp.jsandapp.min.js— added second currency support, better null/NaN handling, and always 2 decimal places on all prices. Fixes sites where minification plugins may loadapp.min.jsinstead ofapp.js.
2.7.0.7
Fixes:
- All prices now display with 2 decimal places (e.g. $10.00 instead of $10) via
formattedPrice()usingtoLocaleStringwithminimumFractionDigits: 2.
2.7.0.6
Fixes:
- Added missing
estimatedPrice,content, andisShoptemplate variables to widget and shortcodelot-content-templatecalls, 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 —
#stripePaymentElementhadhiddenclass that was never removed. Now unhides form on Stripereadyevent and re-hides on modal close.
2.7.0.4
Fixes:
- Fixed
bidspiritApi.getAuctionSettingsData is not a functionerror in getFullPriceInfo — use local auctionSettingsData variable instead of non-existent API method.
2.7.0.3
Fixes:
- Fixed
fullPriceInfo is not definedReferenceError that prevented bid confirmation modal from opening on single lot pages and catalogue pages. - Added missing
getFullPriceInfo(),getCommissonInfoForPrice(), androundToCents()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 definedindisplayBidFormData— removed strayitem: itemfrom house-info-template call where item variable does not exist in scope.
2.5.2.0
Fixes:
- Fixed
item is not definedJavaScript error inauctionIsLive-templateon 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 definedJavaScript 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_loadedfor 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 definedJavaScript error on auction catalog and single lot pages. - Fixed
postAuctionSaleOpened is not definedJavaScript error on auction pages. - Fixed missing
vendor.min.cssandpassword-validation.min.css(404 errors). - Added missing template variables to all
loadTemplatecalls forlot-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.
- Added missing
-
v2.7.2.4 Stable Mar 12, 2026Download v2.7.2.4📦 4.82 MB⚙️ WP 5.2+🔧 PHP 7.2+✓ Tested 6.4
2.7.1.2
Fixes:
- Added missing
vatAndCommission()function inloadBid()— the sales tax display on single lot pages was never being rendered because the code to callloadTemplateforvat-and-commission-templatewas missing fromapp.js. Also added missingsetAuctionItemInfo()call.
2.7.1.1
Fixes:
- 2 decimal places now only appear in the bid modal (Your max bid, Total Price) via
showDecimalsflag. 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-fieldpopulation inauctionInfoInit()from upstream reference.
2.7.0.9
Fixes:
- Fixed fatal error during plugin install/upgrade:
class-stats-database.phprequire failure. Addedfile_existsguard inAF_Stats_Init::activate()and plugin-specific guard inupgrader_process_completehook to prevent running upgrade logic for unrelated plugin updates.
2.7.0.8
Fixes:
- Synced
formattedPrice()across bothapp.jsandapp.min.js— added second currency support, better null/NaN handling, and always 2 decimal places on all prices. Fixes sites where minification plugins may loadapp.min.jsinstead ofapp.js.
2.7.0.7
Fixes:
- All prices now display with 2 decimal places (e.g. $10.00 instead of $10) via
formattedPrice()usingtoLocaleStringwithminimumFractionDigits: 2.
2.7.0.6
Fixes:
- Added missing
estimatedPrice,content, andisShoptemplate variables to widget and shortcodelot-content-templatecalls, 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 —
#stripePaymentElementhadhiddenclass that was never removed. Now unhides form on Stripereadyevent and re-hides on modal close.
2.7.0.4
Fixes:
- Fixed
bidspiritApi.getAuctionSettingsData is not a functionerror in getFullPriceInfo — use local auctionSettingsData variable instead of non-existent API method.
2.7.0.3
Fixes:
- Fixed
fullPriceInfo is not definedReferenceError that prevented bid confirmation modal from opening on single lot pages and catalogue pages. - Added missing
getFullPriceInfo(),getCommissonInfoForPrice(), androundToCents()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 definedindisplayBidFormData— removed strayitem: itemfrom house-info-template call where item variable does not exist in scope.
2.5.2.0
Fixes:
- Fixed
item is not definedJavaScript error inauctionIsLive-templateon 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 definedJavaScript 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_loadedfor 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 definedJavaScript error on auction catalog and single lot pages. - Fixed
postAuctionSaleOpened is not definedJavaScript error on auction pages. - Fixed missing
vendor.min.cssandpassword-validation.min.css(404 errors). - Added missing template variables to all
loadTemplatecalls forlot-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.
- Added missing
-
v2.7.2.2 Stable Mar 11, 2026Download v2.7.2.2📦 4.82 MB⚙️ WP 5.2+🔧 PHP 7.2+✓ Tested 6.4
2.7.1.2
Fixes:
- Added missing
vatAndCommission()function inloadBid()— the sales tax display on single lot pages was never being rendered because the code to callloadTemplateforvat-and-commission-templatewas missing fromapp.js. Also added missingsetAuctionItemInfo()call.
2.7.1.1
Fixes:
- 2 decimal places now only appear in the bid modal (Your max bid, Total Price) via
showDecimalsflag. 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-fieldpopulation inauctionInfoInit()from upstream reference.
2.7.0.9
Fixes:
- Fixed fatal error during plugin install/upgrade:
class-stats-database.phprequire failure. Addedfile_existsguard inAF_Stats_Init::activate()and plugin-specific guard inupgrader_process_completehook to prevent running upgrade logic for unrelated plugin updates.
2.7.0.8
Fixes:
- Synced
formattedPrice()across bothapp.jsandapp.min.js— added second currency support, better null/NaN handling, and always 2 decimal places on all prices. Fixes sites where minification plugins may loadapp.min.jsinstead ofapp.js.
2.7.0.7
Fixes:
- All prices now display with 2 decimal places (e.g. $10.00 instead of $10) via
formattedPrice()usingtoLocaleStringwithminimumFractionDigits: 2.
2.7.0.6
Fixes:
- Added missing
estimatedPrice,content, andisShoptemplate variables to widget and shortcodelot-content-templatecalls, 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 —
#stripePaymentElementhadhiddenclass that was never removed. Now unhides form on Stripereadyevent and re-hides on modal close.
2.7.0.4
Fixes:
- Fixed
bidspiritApi.getAuctionSettingsData is not a functionerror in getFullPriceInfo — use local auctionSettingsData variable instead of non-existent API method.
2.7.0.3
Fixes:
- Fixed
fullPriceInfo is not definedReferenceError that prevented bid confirmation modal from opening on single lot pages and catalogue pages. - Added missing
getFullPriceInfo(),getCommissonInfoForPrice(), androundToCents()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 definedindisplayBidFormData— removed strayitem: itemfrom house-info-template call where item variable does not exist in scope.
2.5.2.0
Fixes:
- Fixed
item is not definedJavaScript error inauctionIsLive-templateon 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 definedJavaScript 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_loadedfor 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 definedJavaScript error on auction catalog and single lot pages. - Fixed
postAuctionSaleOpened is not definedJavaScript error on auction pages. - Fixed missing
vendor.min.cssandpassword-validation.min.css(404 errors). - Added missing template variables to all
loadTemplatecalls forlot-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.
- Added missing
-
v2.7.2.1 Stable Mar 11, 2026Download v2.7.2.1📦 4.81 MB⚙️ WP 5.2+🔧 PHP 7.2+✓ Tested 6.4
2.7.1.2
Fixes:
- Added missing
vatAndCommission()function inloadBid()— the sales tax display on single lot pages was never being rendered because the code to callloadTemplateforvat-and-commission-templatewas missing fromapp.js. Also added missingsetAuctionItemInfo()call.
2.7.1.1
Fixes:
- 2 decimal places now only appear in the bid modal (Your max bid, Total Price) via
showDecimalsflag. 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-fieldpopulation inauctionInfoInit()from upstream reference.
2.7.0.9
Fixes:
- Fixed fatal error during plugin install/upgrade:
class-stats-database.phprequire failure. Addedfile_existsguard inAF_Stats_Init::activate()and plugin-specific guard inupgrader_process_completehook to prevent running upgrade logic for unrelated plugin updates.
2.7.0.8
Fixes:
- Synced
formattedPrice()across bothapp.jsandapp.min.js— added second currency support, better null/NaN handling, and always 2 decimal places on all prices. Fixes sites where minification plugins may loadapp.min.jsinstead ofapp.js.
2.7.0.7
Fixes:
- All prices now display with 2 decimal places (e.g. $10.00 instead of $10) via
formattedPrice()usingtoLocaleStringwithminimumFractionDigits: 2.
2.7.0.6
Fixes:
- Added missing
estimatedPrice,content, andisShoptemplate variables to widget and shortcodelot-content-templatecalls, 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 —
#stripePaymentElementhadhiddenclass that was never removed. Now unhides form on Stripereadyevent and re-hides on modal close.
2.7.0.4
Fixes:
- Fixed
bidspiritApi.getAuctionSettingsData is not a functionerror in getFullPriceInfo — use local auctionSettingsData variable instead of non-existent API method.
2.7.0.3
Fixes:
- Fixed
fullPriceInfo is not definedReferenceError that prevented bid confirmation modal from opening on single lot pages and catalogue pages. - Added missing
getFullPriceInfo(),getCommissonInfoForPrice(), androundToCents()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 definedindisplayBidFormData— removed strayitem: itemfrom house-info-template call where item variable does not exist in scope.
2.5.2.0
Fixes:
- Fixed
item is not definedJavaScript error inauctionIsLive-templateon 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 definedJavaScript 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_loadedfor 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 definedJavaScript error on auction catalog and single lot pages. - Fixed
postAuctionSaleOpened is not definedJavaScript error on auction pages. - Fixed missing
vendor.min.cssandpassword-validation.min.css(404 errors). - Added missing template variables to all
loadTemplatecalls forlot-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.
- Added missing
-
v2.7.2.0 Stable Mar 11, 2026Download v2.7.2.0📦 4.81 MB⚙️ WP 5.2+🔧 PHP 7.2+✓ Tested 6.4
2.7.1.2
Fixes:
- Added missing
vatAndCommission()function inloadBid()— the sales tax display on single lot pages was never being rendered because the code to callloadTemplateforvat-and-commission-templatewas missing fromapp.js. Also added missingsetAuctionItemInfo()call.
2.7.1.1
Fixes:
- 2 decimal places now only appear in the bid modal (Your max bid, Total Price) via
showDecimalsflag. 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-fieldpopulation inauctionInfoInit()from upstream reference.
2.7.0.9
Fixes:
- Fixed fatal error during plugin install/upgrade:
class-stats-database.phprequire failure. Addedfile_existsguard inAF_Stats_Init::activate()and plugin-specific guard inupgrader_process_completehook to prevent running upgrade logic for unrelated plugin updates.
2.7.0.8
Fixes:
- Synced
formattedPrice()across bothapp.jsandapp.min.js— added second currency support, better null/NaN handling, and always 2 decimal places on all prices. Fixes sites where minification plugins may loadapp.min.jsinstead ofapp.js.
2.7.0.7
Fixes:
- All prices now display with 2 decimal places (e.g. $10.00 instead of $10) via
formattedPrice()usingtoLocaleStringwithminimumFractionDigits: 2.
2.7.0.6
Fixes:
- Added missing
estimatedPrice,content, andisShoptemplate variables to widget and shortcodelot-content-templatecalls, 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 —
#stripePaymentElementhadhiddenclass that was never removed. Now unhides form on Stripereadyevent and re-hides on modal close.
2.7.0.4
Fixes:
- Fixed
bidspiritApi.getAuctionSettingsData is not a functionerror in getFullPriceInfo — use local auctionSettingsData variable instead of non-existent API method.
2.7.0.3
Fixes:
- Fixed
fullPriceInfo is not definedReferenceError that prevented bid confirmation modal from opening on single lot pages and catalogue pages. - Added missing
getFullPriceInfo(),getCommissonInfoForPrice(), androundToCents()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 definedindisplayBidFormData— removed strayitem: itemfrom house-info-template call where item variable does not exist in scope.
2.5.2.0
Fixes:
- Fixed
item is not definedJavaScript error inauctionIsLive-templateon 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 definedJavaScript 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_loadedfor 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 definedJavaScript error on auction catalog and single lot pages. - Fixed
postAuctionSaleOpened is not definedJavaScript error on auction pages. - Fixed missing
vendor.min.cssandpassword-validation.min.css(404 errors). - Added missing template variables to all
loadTemplatecalls forlot-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.
- Added missing
-
v2.7.1.2 Stable Mar 10, 2026Download v2.7.1.2📦 5.05 MB⚙️ WP 5.2+🔧 PHP 7.2+✓ Tested 6.4
2.7.1.2
Fixes:
- Added missing vatAndCommission() function in loadBid() — sales tax display on single lot pages was never rendering because the loadTemplate call for vat-and-commission-template was missing from app.js.
-
v2.7.1.1 Stable Mar 10, 2026Download v2.7.1.1📦 5.05 MB⚙️ WP 5.2+🔧 PHP 7.2+✓ Tested 6.4
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.
-
v2.7.1.0 Stable Mar 10, 2026Download v2.7.1.0📦 5.05 MB⚙️ WP 5.2+🔧 PHP 7.2+✓ Tested 6.4
2.7.1.0
Fixes:
- Fixed Buyers Premium value not showing on single lot pages — added missing auction-commission-field population in auctionInfoInit() from upstream reference.
-
v2.7.0.9 Stable Mar 10, 2026Download v2.7.0.9📦 5.05 MB⚙️ WP 5.2+🔧 PHP 7.2+✓ Tested 6.4
2.7.0.9
Fixes:
- Fixed fatal error during plugin install/upgrade: class-stats-database.php require failure. Added file_exists guard and plugin-specific guard in upgrader_process_complete hook.
-
v2.7.0.8 Stable Mar 10, 2026Download v2.7.0.8📦 5.05 MB⚙️ WP 5.2+🔧 PHP 7.2+✓ Tested 6.4
2.7.0.8
Fixes:
- Synced formattedPrice() across both app.js and app.min.js with second currency support, better null/NaN handling, and always 2 decimal places on all prices.
-
v2.7.0.7 Stable Mar 10, 2026Download v2.7.0.7📦 5.05 MB⚙️ WP 5.2+🔧 PHP 7.2+✓ Tested 6.4
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.
-
v2.7.0.6 Stable Mar 10, 2026Download v2.7.0.6📦 5.05 MB⚙️ WP 5.2+🔧 PHP 7.2+✓ Tested 6.4
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.
-
v2.7.0.5 Stable Mar 10, 2026Download v2.7.0.5📦 5.05 MB⚙️ WP 5.2+🔧 PHP 7.2+✓ Tested 6.4
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.
-
v2.7.0.4 Stable Mar 10, 2026Download v2.7.0.4📦 5.05 MB⚙️ WP 5.2+🔧 PHP 7.2+✓ Tested 6.4
2.7.0.4
Fixes:
- Fixed
bidspiritApi.getAuctionSettingsData is not a functionerror in getFullPriceInfo — use local auctionSettingsData variable instead of non-existent API method.
- Fixed
-
v2.7.0.3 Stable Mar 10, 2026Download v2.7.0.3📦 5.05 MB⚙️ WP 5.2+🔧 PHP 7.2+✓ Tested 6.4
2.7.0.3
Fixes:
- Fixed
fullPriceInfo is not definedReferenceError that prevented bid confirmation modal from opening on single lot pages and catalogue pages. - Added missing
getFullPriceInfo(),getCommissonInfoForPrice(), androundToCents()functions ported from upstream. - All three bid submission paths (submitBid, submitBidCatalog, submitBidCatalog3) now correctly pass fullPriceInfo to the modal-bid-template.
- Fixed
-
v2.7.0.2 Stable Mar 09, 2026Download v2.7.0.2📦 4.83 MB⚙️ WP 5.2+🔧 PHP 7.2+✓ Tested 6.4
2.7.0.1
Fixes:
- Fixed catalog sorting (price, most active) not working on the regular (banner) template — sort_by parameter was not being applied to the main WordPress query
- Fixed user tracking (login/registration) not recording data — tracking functions were missing from the loaded JavaScript file
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 definedindisplayBidFormData— removed strayitem: itemfrom house-info-template call where item variable does not exist in scope.
2.5.2.0
Fixes:
- Fixed
item is not definedJavaScript error inauctionIsLive-templateon 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 definedJavaScript 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_loadedfor 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 definedJavaScript error on auction catalog and single lot pages. - Fixed
postAuctionSaleOpened is not definedJavaScript error on auction pages. - Fixed missing
vendor.min.cssandpassword-validation.min.css(404 errors). - Added missing template variables to all
loadTemplatecalls forlot-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.
-
v2.7.0.0 Stable Mar 08, 2026Download v2.7.0.0📦 5.05 MB⚙️ WP 5.2+🔧 PHP 7.2+✓ Tested 6.4
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
-
v2.6.3.0 Beta Mar 08, 2026Download v2.6.3.0📦 5.04 MB⚙️ WP 5.2+🔧 PHP 7.2+✓ Tested 6.4
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
-
v2.6.2.0 Beta Mar 08, 2026Download v2.6.2.0📦 5.04 MB⚙️ WP 5.2+🔧 PHP 7.2+✓ Tested 6.4
2.6.2.0
Fixes:
- Fixed 404 errors on auction/lot pages after DB version update by flushing rewrite rules automatically
-
v2.6.0.0 Beta Mar 08, 2026Download v2.6.0.0📦 5.04 MB⚙️ WP 5.2+🔧 PHP 7.2+✓ Tested 6.4
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)
-
v2.5.9.0 Stable Mar 07, 2026Download v2.5.9.0📦 5.03 MB⚙️ WP 5.2+🔧 PHP 7.2+✓ Tested 6.4
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).
-
v2.5.8.0 Beta Mar 07, 2026Download v2.5.8.0📦 5.03 MB⚙️ WP 5.2+🔧 PHP 7.2+✓ Tested 6.4
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.
-
v2.5.7.0 Beta Mar 07, 2026Download v2.5.7.0📦 5.03 MB⚙️ WP 5.2+🔧 PHP 7.2+✓ Tested 6.4
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.
-
v2.5.6.0 Beta Mar 07, 2026Download v2.5.6.0📦 5.03 MB⚙️ WP 5.2+🔧 PHP 7.2+✓ Tested 6.4
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.
-
v2.5.5.0 Beta Mar 07, 2026Download v2.5.5.0📦 5.03 MB⚙️ WP 5.2+🔧 PHP 7.2+✓ Tested 6.4
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.
-
v2.5.4.0 Stable Mar 07, 2026Download v2.5.4.0📦 5.03 MB⚙️ WP 5.2+🔧 PHP 7.2+✓ Tested 6.4
2.5.4.0
Fixes:
- Fixed item variable not being passed to auctionIsLive-template (was lost during previous file edits).
-
v2.5.3.0 Beta Mar 07, 2026Download v2.5.3.0📦 5.03 MB⚙️ WP 5.2+🔧 PHP 7.2+✓ Tested 6.4
2.5.3.0
Fixes:
- Fixed
item is not definedindisplayBidFormData— removed strayitem: itemfrom house-info-template call where item variable does not exist in scope.
- Fixed
-
v2.5.2.0 Beta Mar 07, 2026Download v2.5.2.0📦 5.03 MB⚙️ WP 5.2+🔧 PHP 7.2+✓ Tested 6.4
2.5.2.0
Fixes:
- Fixed
item is not definedJavaScript error inauctionIsLive-templateon single lot pages. - Fixed statistics table auto-creation running on frontend requests (restricted to admin only).
- Fixed
-
v2.5.1.0 Beta Mar 07, 2026Download v2.5.1.0📦 5.03 MB⚙️ WP 5.2+🔧 PHP 7.2+✓ Tested 6.4
2.5.1.0
Fixes:
- Fixed
hideleadingBidSection is not definedJavaScript 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_loadedfor sites that update without re-activating. - Cleaned up duplicate
AF_Stats_Init::activate()calls in DB update function. - Bumped DB version to 18.
- Fixed
-
v2.5.0.0 Beta Mar 07, 2026Download v2.5.0.0📦 5.03 MB⚙️ WP 5.2+🔧 PHP 7.2+✓ Tested 6.4
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 definedJavaScript error on auction catalog and single lot pages. - Fixed
postAuctionSaleOpened is not definedJavaScript error on auction pages. - Fixed missing
vendor.min.cssandpassword-validation.min.css(404 errors). - Added missing template variables to all
loadTemplatecalls forlot-content-template,leadingBid-template.
-
v2.4.4.0 Stable Mar 06, 2026Download v2.4.4.0📦 4.79 MB⚙️ WP 5.2+🔧 PHP 7.2+✓ Tested 6.4
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.
-
v2.4.3.9 Stable Mar 04, 2026Download v2.4.3.9📦 4.79 MB⚙️ WP 5.2+🔧 PHP 7.2+✓ Tested 6.4
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.
- Added the ability to create a menu item that opens a modal login window. (
-
v2.4.3.8 Stable Mar 02, 2026Download v2.4.3.8📦 4.79 MB⚙️ WP 5.2+🔧 PHP 7.2+✓ Tested 6.4
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.
- Added the ability to create a menu item that opens a modal login window. (
-
v2.4.3.7 Stable Feb 24, 2026Download v2.4.3.7📦 4.79 MB⚙️ WP 5.2+🔧 PHP 7.2+✓ Tested 6.4
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.
- Added the ability to create a menu item that opens a modal login window. (
-
v2.4.3.4 Stable Feb 23, 2026Download v2.4.3.4📦 4.79 MB⚙️ WP 5.2+🔧 PHP 7.2+✓ Tested 6.4
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.
- Added the ability to create a menu item that opens a modal login window. (
-
v2.4.3.3 Stable Feb 23, 2026Download v2.4.3.3📦 5.01 MB⚙️ WP 5.2+🔧 PHP 7.2+✓ Tested 6.9
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.
- Added the ability to create a menu item that opens a modal login window. (
-
v2.4.3.2 Stable Feb 23, 2026Download v2.4.3.2📦 5.01 MB⚙️ WP 5.2+🔧 PHP 7.2+✓ Tested 6.9
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.
- Added the ability to create a menu item that opens a modal login window. (
-
v2.4.3.1 Stable Feb 23, 2026Download v2.4.3.1📦 5.01 MB⚙️ WP 5.2+🔧 PHP 7.2+✓ Tested 6.4
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.
- Added the ability to create a menu item that opens a modal login window. (
-
v2.4.3.0 Stable Feb 23, 2026Download v2.4.3.0📦 5.01 MB⚙️ WP 5.2+🔧 PHP 7.2+✓ Tested 6.4
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.
- Added the ability to create a menu item that opens a modal login window. (
-
v2.4.2.0 Stable Feb 23, 2026Download v2.4.2.0📦 4.79 MB⚙️ WP 5.2+🔧 PHP 7.2+✓ Tested 6.4
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.
- Added the ability to create a menu item that opens a modal login window. (
-
v2.4.1.5 Stable Feb 22, 2026Download v2.4.1.5📦 4.78 MB⚙️ WP 5.2+🔧 PHP 7.2+✓ Tested 6.4
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.
- Added the ability to create a menu item that opens a modal login window. (
-
v2.4.1.4 Stable Feb 21, 2026Download v2.4.1.4📦 4.78 MB⚙️ WP 5.2+🔧 PHP 7.2+✓ Tested 6.4
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.
- Added the ability to create a menu item that opens a modal login window. (
-
v2.4.1.0 Stable Feb 19, 2026Download v2.4.1.0📦 4.78 MB⚙️ WP 5.2+🔧 PHP 7.2+✓ Tested 6.4
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.
- Added the ability to create a menu item that opens a modal login window. (
-
v2.4.0.1 Stable Feb 18, 2026Download v2.4.0.1📦 4.78 MB⚙️ WP 5.2+🔧 PHP 7.2+✓ Tested 6.4
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.
- Added the ability to create a menu item that opens a modal login window. (
-
v2.4.0.0 Stable Feb 17, 2026Download v2.4.0.0📦 4.77 MB⚙️ WP 5.2+🔧 PHP 7.2+✓ Tested 6.4
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.
- Added the ability to create a menu item that opens a modal login window. (
-
v2.3.8.40 Stable Feb 16, 2026Download v2.3.8.40📦 4.99 MB⚙️ WP 5.2+🔧 PHP 7.2+✓ Tested 6.4
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.
- Added the ability to create a menu item that opens a modal login window. (
Plugin Info
Requirements
-
⚙️WordPress5.2 or higher
-
🔧PHP7.2 or higher
-
✓Tested Up ToWordPress 6.4
-
📦File Size9.16 MB