# WB Listora 1.1.0 — Basecamp Bug Triage & Fix Plan

Source: Basecamp "WB Listora" → Bugs column (18 cards). Analyzed 2026-05-31 via parallel code-trace agents.
Branches: both repos on `1.1.0`. Site: http://wb-listora.local

Legend: complexity = trivial / small / medium. **Browser verification mandatory for every fix.**

---

## A. REAL BUGS — need fix (15)

### FREE plugin

| # | Card | Title | Root cause | Files | Cx |
|---|------|-------|-----------|-------|----|
| 1 | 9941185510 | Console 404 on demo import | Admin JS enqueued from `src/admin/admin.js` (stripped in dist); should be `build/admin/admin.js` | `includes/class-assets.php:387` | trivial |
| 2 | 9941186252 | Slow demo import | Synchronous import in wizard POST; `download_url($url, 30)` 30s/image; "all" runs every pack | `demo/class-demo-seeder.php:508,579,618`; `includes/admin/class-setup-wizard.php:163,699-748` | medium |
| 3 | 9932329169 | Action icons dead in My Listings | IAPI dashboard view module not hydrating (all icons dead at once) — needs browser pin | `templates/blocks/user-dashboard/tab-listings.php`; `src/blocks/user-dashboard/view.js`; `src/interactivity/store.js` | small-med |
| 4 | 9932290292 | Map loads after multiple Continue clicks | Leaflet init in hidden/0-size container; single `setTimeout(invalidateSize,200)` races CSS step transition | `src/blocks/listing-submission/view.js:1790,1846,79` | small |
| 5 | 9932186473 | Filter count incorrect + Business tab not highlighted | `activeFilterCount` counts `selectedType` (store.js:251); per-type buttons miss `data-wp-class--is-active`/aria-pressed | `templates/blocks/listing-search/search.php:59-67`; `src/interactivity/store.js:251` | small |
| 6 | 9932168698 | Icons touch container edges | 40px tap-target circle == 40px field height → 0 gap (regression from 2026-05-25 tap-target bump) | `blocks/listing-search/style.css:103-130,13-23` | trivial |
| 7 | 9928220940 | Business Hours missing in preview | `appendBusinessHoursPreview` `hasAny` bails when Flatpickr value not flushed to native input | `src/blocks/listing-submission/view.js:1218-1287,690-708` | small |
| 8 | 9927585174 | Bulk actions in Claims/Reviews | Header "select-all" checkbox has NO JS handler in `admin-pages.js` | `assets/js/admin/admin-pages.js`; markup `class-admin.php:1239,1582` | trivial |
| 9 | 9919933465 | Docs button wrong link | Host hardcoded `wblistora.com/docs/` (dead); should be `store.wbcomdesigns.com/listora/docs/` | `includes/admin/class-settings-page.php:365` | trivial |
| 10 | 9927635866 | Write a Review UI | Button spacing done (8e511d6); 6-point form redesign (star align, label highlight, spacing, borders, hierarchy, theme match) still open | `templates/blocks/listing-reviews/review-form.php`; `blocks/listing-detail/style.css` | medium |
| 11 | 9927933886 | Credits SDK missing src/ fatal | SDK registers `Versions` hook unconditionally even when submodule `src/` absent in dist | `vendor/wbcom-credits-sdk/wbcom-credits-sdk.php:107-119`; `wb-listora.php:577` | small |
| 13 | 9927816084 | Submission Preview not rendering | Either validateStep silently blocks step advance, or buildPreview sections all throw — needs browser pin | `src/blocks/listing-submission/view.js:1070-1140,1348-1397,762-916` | medium |
| 14 | 9927642448 | Import/Export integrity audit | CSV importer bypasses `Term_Helper`; no location import/export; migrator base dup logic; docs overclaim CSV location | `includes/import-export/class-csv-importer.php`, `class-csv-exporter.php`, `class-migration-base.php`; `docs/website/features/locations.md` | medium |
| 15 | 9909608577 | Map clustering OFF crash | clustering-off branch uses `L.layerGroup()` (no `.getBounds()`); `fitMarkersInView` crashes | `src/blocks/listing-map/view.js:86-88,212-218` | small |

### PRO plugin

| # | Card | Title | Root cause | Files | Cx |
|---|------|-------|-----------|-------|----|
| 12 | 9927893041 | Coupon save → headers already sent | POST handled inside render callback + redirect after output; mirror 4d88895 fix (move to admin_init) | `wb-listora-pro/includes/features/class-coupons.php:28-34,707-741,791-796` | small |

---

## B. ALREADY FIXED IN CODE — verify only (3)

| Card | Title | State |
|------|-------|-------|
| 9914777295 | License check still on WP-Cron | FIXED `ecd3213` — scheduling on `init`, AS branch self-heals stale WP-Cron. QA's "still broken" comment is stale. Verify + close. |
| 9881995399 | Pro listora-tools redirect | Titled bug FIXED `4d88895`. Reopen is a *different* issue: `competitor-migration.js` 404 (enqueue-in-render + possibly missing in dist build). Verify original; treat 404 as small follow-up. |
| 9927860832 | My Dashboard 404 | Likely FIXED (#9927424612) — registry-aligned `my-dashboard` slug. Verify on a site with missing page mapping; may need ensure-page. |

---

## C. BROWSER VERIFICATION RESULTS (2026-05-31, combo mode, Playwright)
Screenshots: ~/Documents/work-artifacts/screenshots/2026-05/listora-repro/

| Card | Verdict | Note |
|------|---------|------|
| 9941185510 Console 404 demo import | REPRODUCED | `class-assets.php:389` enqueues `src/admin/admin.js`; 200 locally but 404 in dist (src stripped). Confirmed wrong path. |
| 9919933465 Docs link | REPRODUCED | All docs links → `wblistora.com/docs/...`; domain dead (curl 000). Need `store.wbcomdesigns.com`. |
| 9927893041 PRO coupon headers | REPRODUCED | debug.log: "Cannot modify header information... script-loader.php:2447"; blank page after save; coupon saved. Redirect in render callback. |
| 9932168698 Icons touch edges | REPRODUCED | 44px icon in 45.6px field, padding:0 → ~0.8px gap (flush). |
| 9932186473 Filter count + tab highlight | REPRODUCED | Badge 0→1 on Business tab; type tab missing `is-active`. Both confirmed. |
| 9928220940 Business hours in preview | REPRODUCED | Set 09:00–17:00 Mon; absent from preview content. |
| 9932329169 Action icons dead | REPRODUCED | services panel stays display:none; more-actions button has NO data-wp-context (no listing id) → empty dropdown. view.js loads 200. |
| 9927635866 Write a Review UI | REPRODUCED | Mobile 390px: Ambiance row wraps, submit not full-width, no @media for criteria stack. |
| 9909608577 Map clustering OFF crash | INCONCLUSIVE (code-confirmed) | No clustering-OFF map exists on frontend to trigger; `L.layerGroup().getBounds()` crash confirmed in source. |
| 9941186252 Slow demo import | INCONCLUSIVE→real | ~9s for 8 listings (~1.1s each); "All" ≈100s. No error but genuinely slow. |
| 9932290292 Map multi-click | NOT REPRODUCED | Map rendered fully on first reveal (21 tiles, 0 grey). Could not trigger. |
| 9927816084 Submission preview | NOT REPRODUCED | Preview rendered real content; no placeholder; no `[wb-listora] preview section failed` errors. |
| 9927860832 My Dashboard 404 | NOT REPRODUCED (fix verified) | `/my-listings/#listings` + edit link both 200. Already-fixed code holds. |
| 9927585174 Bulk actions select-all | NOT REPRODUCED | select-all checked all rows (Reviews 50/50, Claims 40/40). Contradicts code-trace — appears wired/fixed now. |
| 9881995399 listora-tools redirect + competitor 404 | NOT REPRODUCED (fix verified) | Clean redirect, no header warning; competitor-migration.js 200 from build/. |
| 9927933886 Credits SDK fatal | NOT REPRODUCED (expected) | Admin loads, no fatal locally (submodule src present). Dist/packaging-only risk. |
| 9914777295 License cron | NOT A BUG | `wb_listora_pro_license_check` is on Action Scheduler (pending next 2026-06-07), NOT WP-Cron. EDD SDK's `edd_sl_sdk_weekly_*` on WP-Cron is a separate update-check. Card premise stale → close. |

### Fix decision buckets
- **CONFIRMED — fix now (9):** 9941185510, 9919933465, 9927893041, 9932168698, 9932186473, 9928220940, 9932329169, 9927635866, 9909608577 (code-confirmed).
- **REAL but perf (1):** 9941186252 slow import.
- **CANNOT REPRODUCE — defensive/optional (2):** 9927816084, 9932290292 — apply hardening from code-trace but no live repro; verify carefully.
- **ALREADY FIXED / NOT A BUG — verify & close on Basecamp (5):** 9927860832, 9881995399, 9914777295, 9927585174, 9927933886 (9927933886 = add defensive guard for dist even though not reproducible).

## Execution notes
- JS/CSS in `src/` and many `blocks/*/view.js` ship from `build/` → must `npm run build` after edits.
- Free repo: stale unstaged `package-lock.json` (leave/ignore).
- Each fix: reproduce in browser → fix at root cause → rebuild if needed → browser-verify (390px + desktop) → screenshot → commit on `1.1.0`.
- Free/Pro lockstep for any shared/changelog changes.

---

## D. PRODUCT-READINESS AUDIT FINDINGS (2026-06-03)

Net-new findings from the AutoVAP full-lens audit of the `1.1.0` branch (security · performance · UX · QA · standards). These are **complementary** to the Basecamp bugs above — proactive release-discipline + big-site-scale + standards items, not customer-reported. Full reports: `audit/AUDIT_VERDICT_2026-06-03.md` (free) and `../wb-listora-pro/audit/AUDIT_VERDICT_2026-06-03.md` (pro). Journey = `fix` (minimal change) / `improve` (refactor/harden).

**Verdict:** both plugins **NOT shippable** until the version-skew blocker closes; **sellable with polish** otherwise.

### FREE plugin

| # | Sev | Journey | Task | File:line |
|---|-----|---------|------|-----------|
| AUD-F1 | **Blocker** | fix | Bump version `1.0.5 → 1.1.0` (header + `WB_LISTORA_VERSION`); re-run `bin/build-release.sh` | `wb-listora.php:6,22` |
| AUD-F2 | Major | improve | Kill N+1 in listing-grid SSR — batch-prefetch ratings before the loop (mirror REST controller line 177) | `blocks/listing-grid/render.php:137-142`, `includes/class-template-helpers.php:461-466` |
| AUD-F3 | Major | improve | Paginate admin Reviews & Claims (LIMIT 50 → `?paged` + COUNT(*) + `paginate_links()`) | `includes/admin/class-admin.php:1177,1520` |
| AUD-F4 | Major | improve | Cap unbounded calendar recurring query (`LIMIT 500` + 42-day window pre-filter) | `blocks/listing-calendar/render.php:68-82` |
| AUD-F5 | Minor | fix | `$wpdb->prepare()` the `SHOW TABLE STATUS LIKE` query | `includes/class-cli-commands.php:98` |
| AUD-F6 | Minor | improve | Stop autoloading `wb_listora_settings` + notification-log options (`autoload=no`) | `includes/rest/class-settings-controller.php`, `includes/workflow/class-notifications.php` |
| AUD-F7 | Minor | improve | Raise customer-facing `--sm` button tap target 32 → 36px (scope admin to 32px) | `assets/css/listora-components.css:311` |
| AUD-F8 | Minor | improve | Consolidate 7 CSS breakpoints → canonical 3 (480/640/1024) | `blocks/*/style.css` |
| AUD-F9 | Minor | fix | Refresh stale Free→Pro coupling cache before tag (`php bin/cleanup-duplicate-detect.php`) | `audit/derived/cross-plugin-coupling.json` |
| AUD-F10 | Polish | improve | Document dashicon→Lucide migration map; start PHPStan baseline burn-down | `includes/core/class-listing-type-registry.php:331-340`, `phpstan-baseline.neon` |

### PRO plugin

| # | Sev | Journey | Task | File:line |
|---|-----|---------|------|-----------|
| AUD-P1 | **Blocker** | fix | Bump version `1.0.5 → 1.1.0` (header + `WB_LISTORA_PRO_VERSION`) + free-lockstep check `1.0.0 → 1.1.0` | `wb-listora-pro.php:6,20,114` |
| AUD-P2 | Major | improve | Batch-fetch `GET /dashboard/needs` (N+1+M → keyed `IN()` + `get_posts/users include`) + `no_found_rows` | `includes/rest/class-need-responses-controller.php:354-413` |
| AUD-P3 | Major | improve | Paginate `send_alerts()` `get_users()` (batch 100 via number/offset, reschedule via AS) | `includes/features/class-advanced-search.php:~246` |
| AUD-P4 | Major | improve | Replace `posts_per_page=-1` count with `SELECT COUNT(*)` | `includes/features/class-reverse-listings.php:166-186` |
| AUD-P5 | Minor | improve | Fix invisible focus ring on need-respond inputs (transparent → token) | `assets/css/pro-frontend.css:1288` |
| AUD-P6 | Minor | improve | Replace raw hex (`#1e7e34`, `#fff`) with tokens (dark-mode safe) | `assets/css/pro-admin.css:2828,3010,3107`, `blocks/comparison/style.css:223` |
| AUD-P7 | Minor | improve | `add_option(..., false)` for notification_queue / map_styles / credit_packs (no autoload) | `includes/class-activator.php:221` |
| AUD-P8 | Polish | improve | Rate-limit public (`__return_true`) REST endpoints (IP transient, ~60/min) | multiple REST controllers |
| AUD-P9 | Polish | improve | Enqueue `analytics_tracker.js` in footer | `includes/features/class-analytics.php:263-270` |
| AUD-P10 | Polish | fix | Defence-in-depth ownership check on saved-search PATCH/DELETE | `includes/features/class-advanced-search.php` |

### Suggested 1.1.0 order (audit items)
1. **AUD-F1 + AUD-P1 together** (shared version-bump blocker — Free/Pro lockstep) — unblocks the release.
2. Big-site majors: AUD-F2/F3/F4, AUD-P2/P3/P4 (the real scale risks at 2000+ rows/users).
3. Minors/polish folded into the relevant Basecamp-bug PRs where files overlap.
4. Re-run `/wp-plugin-smoke combo` at 1.1.0 (must show `release_version: 1.1.0`, empty failures) before tagging.

---

## E. BASECAMP QA BUGS — 2026-06-02 (audited 2026-06-03)

New cards in the QA Bugs column (project 47045113), code-traced to root cause. Reported on a BuddyBoss/Reign/BuddyX-Pro 5.1.0 stack (won't reproduce on directory.local's Twenty Twenty-Five sandbox — these are code-trace verdicts).

**REPLICATED 2026-06-03 (no blind fixes):** BG-1 confirmed via php `extract()` repro (no `view_data` key → undefined). BG-2 confirmed live — `.leaflet-container`/`.map-picker` have no `position` in CSS; `getComputedStyle(.map-picker).position="static"` before Leaflet's JS injects inline `position:relative` (so the overflow is the JS-timing race; CSS fix makes it deterministic). BG-3 confirmed — BuddyX uses `[data-bx-mode="dark"]`, loaded `buddyx.css` bridge has zero such selectors. BG-4 reproduced in browser — two "Features" tabs (`tab=features` + `tab=pro-features`), identical label/icon.

| # | Card | Verdict | Root cause (file:line) | Fix | Plugin | Cx |
|---|------|---------|------------------------|-----|--------|----|
| BG-1 | 9952578127 — PHP `$view_data` warning in My Listings/My Reviews | real bug `fix` | `wb_listora_get_template()` extract()s an args array with no `view_data` key; BP loop templates use `$view_data` only as hook payload (`templates/bp/listings-loop.php:29/81`, `reviews-loop.php:31/98`). Free's `blocks/listing-card/render.php:162` self-references (`$view_data['view_data']=$view_data;`) — Pro's `render_my_listings/reviews` omit it. | Add `$view_data['view_data'] = $view_data;` in `includes/features/class-buddy-press-integration.php` (~624 listings, ~696 reviews) before each `wb_listora_get_template()`. Optional `?? []` template defaults. | **Pro** | trivial |
| BG-2 | 9952543239 — Map overlaps layout + Business Hours misaligned (Add Listing → Details) | bug `fix` | (a) vendored `assets/vendor/leaflet.css` has `position:relative` stripped from `.leaflet-container`; nothing re-supplies it on `.listora-submission__map-picker` → absolute panes + `z-index:1000` controls escape the 250px box. (b) stale `.listora-submission__hours-times input[type=time]{width:110px}` (`blocks/listing-submission/style.css:706`) fights the new icon-wrapper; no `min-width:0` on flex children. | (a) add `position:relative` to `.listora-submission__map-picker` (NOT the vendor file). (b) drop the 110px rule; give wrapper stable width + `min-width:0`; migrate literal rems→tokens. CSS only (+ RTL rebuild). Adjacent-check `blocks/listing-map` for same leaflet issue. | **Free** | small |
| BG-3 | 9953255233 — Dark-mode invisible text (Add Listing, My Listings Overview/Reviews/Analytics) | bug `fix`+`improve` | BuddyX 5.1.0 sets `<html data-bx-mode="dark">`, but Listora reacts only to `[data-theme=dark]`/`[data-listora-dark]` (`listora-base.css:93-94`) + bridge to legacy `body.buddyx-dark-theme` (`buddyx-pro.css:89`) — and the loaded `themes/buddyx.css` bridge has NO dark block. Tokens stay light on dark surfaces. Secondary: `--listora-card-bg`/`--listora-border`/`--listora-input-*` (`listora-base.css:14,43,46-50`) hardwired to light `--wp--preset` values, so they wouldn't flip even if triggered. | CSS only in **Free**: add `data-bx-mode="dark"` (+auto/prefers) trigger to `themes/buddyx.css` (new dark block) + `themes/buddyx-pro.css:89`; re-point the 5 alias tokens to `--listora-*` semantics first, preset fallback last. Pro Analytics is correctly token-driven → inherits the fix, no Pro change. RTL rebuild. | **Free** | small-med |
| BG-4 | 9952700845 — Duplicate "Features" labels after Pro activation | **suggestion** `improve` | Pro injects its own `pro-features` nav tab + parallel features screen (`class-pro-plugin.php:209-213, 2749`) instead of consuming Free's EXISTING `wb_listora_features_registry` filter (`class-features.php:106`) → two identically-labeled "Features" nav items. | **DECIDED 2026-06-03 → (A) MERGE:** Pro registers its 29 toggles into Free's Features screen via the existing `wb_listora_features_registry` filter; remove Pro's `pro-features` parallel tab; Free renders Free/Pro sub-groups under one Features screen. MUST preserve Pro's separate `wb_listora_pro_features` option + the `update_option_wb_listora_pro_features` AS-job-cancel side-effect, and keep INV-3 green (Pro reaches Free only via the filter). Repoint `#pro-features` deep-links. | Free+Pro | med |

**Order:** BG-1 (trivial) → BG-2 (CSS) → BG-3 (CSS) → BG-4 (after owner picks A or B). BG-1/2/3 are real defects for 1.1.0; per the Basecamp workflow each gets a fix + browser-verify + comment + move to *Ready for Testing*. BG-4 is a suggestion — reply on-card with the recommendation, code only after the owner decides.
