upskill-event-manager/Status.md
ben fcd55fd164 feat(find-training): Differentiate measureQuick Certified Champions from Trainers
Champions are identified by "Certified measureQuick Champion" certification.
Unlike Trainers, Champions do not offer public training, so they display
differently:

- White marker outline (vs green for Trainers)
- Show only state, not city, in sidebar and info windows
- No "View Profile" button or modal popup on click
- Sorted to end of trainer list (after all Trainers)
- Non-clickable card styling

Code review fixes (Gemini 3):
- Fixed location formatting to handle empty city gracefully
- Added secondary sort by name for stable ordering

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-02 02:01:15 -04:00

40 KiB
Raw Blame History

HVAC Community Events - Project Status

Last Updated: February 2, 2026 Current Session: Champion Differentiation on Find Training Map Version: 2.2.6 (Deployed to Production)


🎯 NEXT SESSION - CAPTCHA IMPLEMENTATION

Status: 📋 PLANNED

Objective: Add CAPTCHA to all user-facing forms to prevent spam and bot submissions.

Forms to Update:

  • Training login form
  • Trainer registration form
  • Contact forms (trainer, venue)
  • Any other public-facing forms

🎯 CURRENT SESSION - CHAMPION DIFFERENTIATION ON FIND TRAINING (Feb 2, 2026)

Status: COMPLETE - Deployed to Production

Objective: Differentiate measureQuick Certified Champions from Trainers on the Find Training map. Champions do not offer public training, so they should be displayed differently.

Changes Made

  1. Backend Data (includes/find-training/class-hvac-training-map-data.php)

    • Added is_champion flag for trainers with "Certified measureQuick Champion" certification
    • Champions return empty city field (only state shown)
  2. Champion Marker Icon (assets/js/find-training-map.js)

    • Added getChampionIcon() method with white outline (vs green for Trainers)
    • Champions use distinct visual appearance on map
  3. Sidebar Cards (assets/js/find-training-map.js)

    • Champions show only state (e.g., "Ohio" not "Canton, Ohio")
    • Champions have non-clickable cards (no modal popup)
    • Added hvac-champion-card CSS class
  4. Info Windows (assets/js/find-training-map.js)

    • Champions show only state in location
    • No "View Profile" button for Champions
    • Fixed location formatting to handle empty city gracefully
  5. Sorting (assets/js/find-training-map.js)

    • Champions sorted to end of trainer list
    • Secondary sort by name for stable ordering
    • Applied to both loadMapData and loadTrainerDirectory
  6. CSS Styling (assets/css/find-training-map.css)

    • Champion cards have non-clickable appearance
    • No hover effects (cursor: default, no transform/shadow)

Files Modified

File Change
includes/find-training/class-hvac-training-map-data.php Added is_champion flag, empty city for champions
assets/js/find-training-map.js Champion icon, card display, click prevention, sorting
assets/css/find-training-map.css Champion card non-clickable styling

Verification (Staging)

  • API returns is_champion: true for 18 champions
  • Champions have empty city in API response
  • Champions sorted to end of list
  • Champion cards show only state
  • Clicking champion card does NOT open modal
  • Clicking trainer card DOES open modal (regression test)

Code Review Findings (Gemini 3)

  • Fixed: Location formatting bug - empty city could show ", California"
  • Fixed: Unstable sort order - added secondary sort by name

📋 PREVIOUS SESSION - TABBED INTERFACE FOR FIND TRAINING (Feb 1, 2026)

Status: COMPLETE - Deployed to Production

Objective: Refactor the Find Training page sidebar from a single trainer list to a tabbed interface with Trainers, Venues, and Events tabs.

Changes Made

  1. Tab Navigation System (templates/page-find-training.php)

    • Replaced "42 trainers" header with three tabs: Trainers | Venues | Events
    • Each tab displays dynamic count in parentheses
    • ARIA accessibility attributes (role="tablist", role="tab", aria-selected)
    • Keyboard navigation (arrow keys, Home, End)
  2. Visibility Toggles Relocated

    • Moved from map overlay to sidebar header
    • Colored dots (teal/orange/purple) match marker colors
    • Only control map marker visibility, not tab content
  3. Venue Cards (assets/js/find-training-map.js)

    • Name with building icon
    • City, State location
    • "X upcoming events" count
  4. Event Cards (assets/js/find-training-map.js)

    • Date badge showing month/day
    • Event title
    • Venue name
    • Cost display
    • "Past" badge for past events
  5. Info Modal (templates/page-find-training.php)

    • "What is Upskill HVAC?" section
    • "How to Use" instructions
    • Map Legend (trainer/venue/event markers)
  6. Context-Aware Search (assets/js/find-training-filters.js)

    • Placeholder changes based on active tab
    • Client-side filtering for instant results (150ms debounce)
    • Falls back to server-side when filters active
  7. CSS Styling (assets/css/find-training-map.css)

    • Tab navigation container and button styles
    • Venue card and event card layouts
    • Info button and modal styling
    • Responsive adjustments for tablet/mobile

Files Modified

File Change
templates/page-find-training.php Tab navigation, panels, info modal
assets/js/find-training-map.js Tab switching, card creators, grid renderers
assets/js/find-training-filters.js Context-aware search, client-side filtering
assets/css/find-training-map.css ~300 lines new CSS for tabs, cards, modal
includes/class-hvac-plugin.php Version bump 2.2.5 → 2.2.6 (CDN cache bust)

Issue Resolved: CDN Cache

Problem: After deployment, browser loaded old JavaScript without new initTabs method.

Root Cause: CDN cached old assets. Deploy script clears WP/OPcache but not CDN edge cache.

Fix: Bumped HVAC_VERSION from 2.2.5 to 2.2.6, changing script URL query string to force cache refresh.

Verified on Staging

  • 42 trainers tab count
  • 9 venues tab count
  • 8 events tab count
  • Tab switching works with proper ARIA attributes
  • Venue cards display correctly
  • Event cards with date badges display correctly
  • Info modal opens and displays content
  • Visibility toggles control map markers

📋 PREVIOUS SESSION - MEASUREQUICK APPROVED TRAINING LABS (Feb 1, 2026)

Status: COMPLETE - Deployed to Staging, Venues Displaying Correctly

Objective: Transform /find-training to showcase only measureQuick Approved Training Labs with venue categories, equipment/amenities tags, and contact forms.

  1. Venue Taxonomies Created (includes/class-hvac-venue-categories.php NEW)

    • venue_type - For lab classification (e.g., "measureQuick Approved Training Lab")
    • venue_equipment - Furnace, Heat Pump, AC, Mini-Split, Boiler, etc.
    • venue_amenities - Coffee, Water, Projector, WiFi, Parking, etc.
    • All taxonomies registered on tribe_venue post type
  2. 9 Approved Training Labs Configured (via WP-CLI script)

    • Fast Track Learning Lab (ID: 6631) - Joe Medosch
    • Progressive Training Lab (ID: 6284) - Samantha Brazie
    • NAVAC Technical Training Center (ID: 6476) - Andrew Greaves
    • Stevens Equipment Supply - Phoenix (ID: 6448) - Robert Cone
    • San Jacinto College South Campus (ID: 6521) - Terry McWilliams
    • Johnstone Supply - Live Fire Training Lab (ID: 4864) - Dave Petz
    • Stevens Equipment Supply - Johnstown (ID: 1648) - Phil Sweren
    • TruTech Tools Training Center (NEW) - Val Buckles
    • Auer Steel & Heating Supply (NEW) - Mike Breen
  3. Map Data Filtered by Taxonomy

    • get_venue_markers() now includes tax_query for mq-approved-lab term
    • Only approved training labs appear as venue markers
    • Equipment, amenities, and POC data included in venue info
  4. Venue Modal Enhanced

    • Equipment badges (teal outline chips)
    • Amenities badges (gray outline chips)
    • Contact form with name, email, phone, company, message
    • POC receives email notification on submission
  5. 6 POC Trainer Accounts Created

    • Samantha Brazie, Andrew Greaves, Terry McWilliams
    • Phil Sweren, Robert Cone, Dave Petz
    • All with hvac_trainer role and approved status

Files Created

File Description
includes/class-hvac-venue-categories.php Venue taxonomy registration (singleton)
scripts/setup-approved-labs.php WP-CLI script to configure all labs
scripts/check-venue-coordinates.php Diagnostic script to verify venue coordinates
scripts/geocode-approved-labs.php Geocode venues missing coordinates

Files Modified

File Change
includes/class-hvac-plugin.php Load venue categories class
includes/find-training/class-hvac-training-map-data.php Add tax_query filter, include equipment/amenities
includes/class-hvac-ajax-handlers.php Add venue contact form AJAX handler
templates/page-find-training.php Add equipment/amenities badges, contact form
assets/js/find-training-map.js Render badges, bind contact form handler
assets/css/find-training-map.css Equipment/amenities badge styles

Issue Resolved: Venues Now Displaying on Map

Root Cause: venue_type taxonomy wasn't being registered when get_venue_markers() ran.

HVAC_Venue_Categories::instance() was instantiated at 'init' priority 5, but then tried to add hooks to 'init' priority 5 for taxonomy registration. Since WordPress was already processing priority 5 handlers, the hook never fired.

Fix Applied:

  1. includes/class-hvac-venue-categories.php - Added did_action('init') check in constructor

    • If 'init' has already fired, call register_taxonomies() and create_default_terms() directly
    • Otherwise, use the standard hook approach
  2. includes/find-training/class-hvac-training-map-data.php - Fixed HTML entity encoding

    • Venue names now use html_entity_decode() to properly display & and characters
    • Event titles also fixed

Result:

  • All 9 approved training labs now display as orange venue markers on the map
  • Venue names display correctly (e.g., "Auer Steel & Heating Supply" not "Auer Steel &...")
  • Marker clustering works with mixed trainer/venue markers

📋 PREVIOUS SESSION - FIND TRAINING PAGE ENHANCEMENTS (Feb 1, 2026)

Status: COMPLETE - Deployed to Production

Objective: Improve Find Training page UX with viewport sync and marker hover interactions.

Changes Made

  1. Viewport Sync - Sidebar now shows only trainers visible in current map area

    • Added visibleTrainers array to track filtered trainers
    • Added syncSidebarWithViewport() method filtering by map bounds
    • Map idle event triggers sync on pan/zoom
    • Count shows "X of Y trainers" when zoomed in
  2. Marker Hover Interaction - Info window appears on hover

    • Added mouseover event listener to trainer/venue markers
    • Set optimized: false on markers for reliable hover events
    • Hover shows info window preview with "View Profile" button
    • Click on "View Profile" opens full modal with contact form
  3. Legacy URL Redirects

    • /find-a-trainer//find-training/ (301 redirect)
    • /find-trainer//find-training/ (301 redirect)
    • Removed old page from Page Manager

Files Modified

File Change
assets/js/find-training-map.js Added viewport sync, hover events, optimized:false
assets/js/find-training-filters.js Updated filter handler for visibleTrainers
includes/class-hvac-route-manager.php Added legacy URL redirects
includes/class-hvac-page-manager.php Removed find-a-trainer page definition
includes/class-hvac-plugin.php Version bumped to 2.2.4

Verified Behavior

  • Hover over marker → Info window appears immediately
  • Click "View Profile" → Full modal with trainer details + contact form
  • Pan/zoom map → Sidebar updates to show visible trainers only
  • Legacy URLs redirect to new page

📋 PREVIOUS SESSION - FIND TRAINING PAGE IMPLEMENTATION (Jan 31 - Feb 1, 2026)

Status: COMPLETE - Deployed to Production

Objective: Replace the buggy MapGeo-based /find-a-trainer page with a new /find-training page built from scratch using Google Maps JavaScript API.

Why This Change

The existing IGM/amCharts implementation had a fundamental bug that corrupted marker coordinates (longitude gets overwritten with latitude). After multiple fix attempts, building fresh with Google Maps API provides:

  • Full control over marker data
  • No third-party plugin dependencies
  • Better long-term maintainability
  • Ability to show both trainers AND venues

Files Created (8 new files)

File Description
includes/find-training/class-hvac-find-training-page.php Main page handler (singleton), AJAX endpoints, asset enqueuing
includes/find-training/class-hvac-training-map-data.php Data provider for trainer/venue markers with caching
includes/find-training/class-hvac-venue-geocoding.php Auto-geocoding for TEC venues via Google API
templates/page-find-training.php Page template with map, filters, modals
assets/js/find-training-map.js Google Maps initialization, markers, clustering
assets/js/find-training-filters.js Filter handling, geolocation, AJAX
assets/css/find-training-map.css Complete responsive styling
assets/images/marker-trainer.svg Teal person icon for trainers
assets/images/marker-venue.svg Orange building icon for venues

Files Modified (3 files)

File Change
includes/class-hvac-page-manager.php Added find-training page definition
includes/class-hvac-plugin.php Load new find-training classes
includes/class-hvac-ajax-handlers.php Added contact form AJAX handler

Multi-Model Code Review Findings & Fixes

Ran comprehensive code review using GPT-5, Gemini 3, and Zen MCP tools. Found and fixed 6 issues:

# Severity Issue Fix
1 CRITICAL Missing hvac_submit_contact_form AJAX handler Added full handler with rate limiting, validation, email
2 HIGH XSS risk in InfoWindow onclick handlers Replaced with DOM creation + addEventListener
3 MEDIUM Uncached filter dropdown SQL queries Added wp_cache with 1-hour TTL
4 MEDIUM AJAX race condition on rapid filters Added request abort handling
5 LOW Hardcoded /trainer/registration/ URL Changed to site_url()
6 LOW alert() for geolocation errors Added inline dismissible notification

Features Implemented

  • Google Maps with custom trainer/venue markers
  • MarkerClusterer for dense areas
  • Filter by State, Certification, Training Format
  • Search by name/location
  • "Near Me" geolocation button
  • Trainer/Venue toggle switches
  • Trainer profile modal with contact form
  • Venue info modal with upcoming events
  • Trainer directory grid below map
  • 301 redirect from /find-a-trainer to /find-training
  • Auto-geocoding for new venues
  • Rate-limited batch geocoding for existing venues

Deployment Status

  • Deployed to staging
  • Map loads with markers and clustering
  • Filters working (state, certification, format)
  • Contact form functional
  • Deployed to production

📋 PREVIOUS SESSION - E2E TESTING & BUG FIXES (Feb 1, 2026)

Status: COMPLETE - Deployed to Staging, Ready for Production

Objective: Deploy security fixes to staging, run E2E tests, fix discovered bugs, and validate all functionality.

Deployment & Testing Summary

  1. Deployed to Staging - All 12 security fixes from previous session
  2. E2E Tests Passed - Master trainer pages, security endpoints verified
  3. Discovered & Fixed 2 Critical Bugs - Trainers table, event pages
  4. Created E2E Testing Skill - .claude/commands/e2e-visual-test.md
  5. Added Staging Email Filter - Prevents accidental user spam

Bugs Found & Fixed

Bug Severity Root Cause Fix
Trainers table empty HIGH ajax_filter_trainers() used complex SQL that returned empty; count_trainers_by_status() only queried hvac_trainer role Rewrote to use get_trainers_table_data() (same as working dashboard); fixed role query to include both roles
Event pages blank HIGH Template path mismatch: code referenced page-trainer-event-manage.php but file is page-manage-event.php Fixed path in class-hvac-event-manager.php:138

Files Modified (4 files)

  1. includes/class-hvac-master-trainers-overview.php

    • Rewrote ajax_filter_trainers() to use reliable get_trainers_table_data()
    • Fixed count_trainers_by_status() to include hvac_master_trainer role
    • Now shows 53 trainers, 5 active (was showing 0)
  2. includes/class-hvac-event-manager.php

    • Fixed template path: page-trainer-event-manage.phppage-manage-event.php
    • Event creation form now fully functional
  3. hvac-community-events.php

    • Added staging email filter (only ben@tealmaker.com receives emails)
    • Protects real users from test emails during development
  4. .claude/commands/e2e-visual-test.md (new)

    • Created E2E visual testing skill for Playwright MCP browser tools
    • Documents login procedure, test sequence, credentials

E2E Test Results

Feature Status Notes
Master Trainer Login PASS Custom /training-login/ works
Master Dashboard PASS Stats, tables, AJAX functional
Trainers Table PASS 53 trainers displayed correctly
Announcements PASS Modal opens, form accessible
Event Creation PASS Full form with all TEC fields
Certificate Reports PASS Empty state (needs events)
Security Endpoints PASS 4/4 properly return 401/400

Staging Email Protection

Emails on staging are now filtered:

  • Allowed: ben@tealmaker.com, ben@measurequick.com
  • Blocked: All other recipients (logged for debugging)
  • Subject Prefix: [STAGING] added to allowed emails

Next Steps

  1. Deploy to production: ./scripts/deploy.sh production
  2. Verify production functionality
  3. Monitor for any issues

📋 PREVIOUS SESSION - MULTI-MODEL SECURITY CODE REVIEW (Jan 31, 2026)

Status: COMPLETE - Deployed to Staging

Objective: Comprehensive security and business logic code review using 4 AI models (GPT-5, Gemini 3, Kimi K2.5, Zen MCP) across 11 critical files (~9,000 lines).

Critical Issues Found & Fixed (12 total)

ID Severity Issue File
C1 CRITICAL Passwords stored in transients class-hvac-registration.php
U1 CRITICAL O(3600) token verification loop (DoS) class-hvac-ajax-security.php
U2 HIGH remove_all_actions() breaks WP isolation class-hvac-plugin.php
C2 HIGH Encryption key in same database as data class-hvac-secure-storage.php
M3 HIGH Revoked certificates still downloadable class-certificate-manager.php
U3 HIGH Security headers not applied to AJAX class-hvac-ajax-security.php
C3 MEDIUM IP spoofing undermines rate limiting class-hvac-security.php
M1 MEDIUM Weak CSP with unsafe-eval class-hvac-ajax-security.php
C5 MEDIUM Duplicate component initialization class-hvac-plugin.php
U9 MEDIUM File-scope side-effect initialization class-hvac-trainer-profile-manager.php
U11 LOW Timezone inconsistency in cert numbers class-certificate-manager.php
U4 HIGH zoho-config.php not in .gitignore .gitignore

Deliverables

  • Full Report: MULTI-MODEL-CODE-REVIEW-REPORT.md
  • 12 Security Fixes: All implemented and deployed to staging

📋 PREVIOUS SESSION - MASTER TRAINER PROFILE EDIT ENHANCEMENT (Jan 9, 2026)

Status: COMPLETE - Deployed to Production

Objective: Fix broken button styling and add all trainer profile fields to the master trainer profile edit page.

Issues Fixed:

  1. Button Styling Broken - "Back to Dashboard" and "Cancel" buttons appeared faded/invisible due to CSS conflicts with theme
  2. Missing Profile Fields - Only showing basic name fields, needed all trainer profile fields
  3. No Password Reset - Master trainers couldn't trigger password resets for trainers they manage

Changes Made

  1. Fixed Button Styling (templates/page-master-trainer-profile-edit-simple.php)

    • Added scoped CSS with new class names (hvac-btn-primary, hvac-btn-secondary, hvac-btn-outline)
    • Avoids theme CSS conflicts by using page-specific selectors
    • Proper colors, hover states, and responsive behavior
  2. Added All Profile Fields (6 complete sections)

    • Profile Settings: Visibility (Public/Private)
    • Certification Information: Status, Type, Date Certified
    • Personal Information: Name, Email, LinkedIn URL, Bio
    • Professional Information: Accreditation, Training Audience/Formats/Locations/Resources (checkboxes)
    • Business Information: Business Type, Revenue Target, Application Details
    • Location Information: City, State, Country, Coordinates with re-geocode button
  3. Added Password Reset Button

    • New "Send Password Reset Email" button in Personal Information section
    • Uses WordPress built-in retrieve_password() function
    • Shows status feedback (Sending... / Sent! / Error)
    • Requires master trainer or admin permissions
    • All actions logged for audit trail
  4. Added AJAX Handler (includes/class-hvac-ajax-handlers.php)

    • New hvac_send_password_reset endpoint
    • Nonce verification, permission checks, input validation
    • Secure implementation using WordPress core functions

Files Modified

  • templates/page-master-trainer-profile-edit-simple.php - Complete rewrite with all fields
  • includes/class-hvac-ajax-handlers.php - Added password reset handler

URLs

  • Production: https://upskillhvac.com/master-trainer/edit-trainer-profile/?user_id=75
  • Staging: https://upskill-staging.measurequick.com/master-trainer/edit-trainer-profile/?user_id=75

📋 PREVIOUS SESSION - TEC COMMUNITY EVENTS DEPENDENCY ANALYSIS (Jan 5, 2026)

Status: COMPLETE - Documented as Technical Debt

Objective: Analyze whether "The Events Calendar: Community" (TEC CE) plugin is still being used after recent refactoring.

Findings:

  • The plugin still actively relies on TEC CE for event creation/editing
  • Core shortcode [tribe_community_events] is used in 7 template/class files
  • TEC CE hooks are used for field processing and form customization
  • HVAC_Event_Manager has custom CRUD capabilities but production paths use TEC CE

Removal Scope:

  • Estimated effort: 9-14 days of development
  • Key work: Custom forms, date pickers, validation, template updates, testing
  • Risk: Recurring events complexity, Event Tickets integration

Decision: Deferred as technical debt. Current implementation is functional and stable.

Deliverables

  1. Analysis Report: docs/reports/TEC-COMMUNITY-EVENTS-DEPENDENCY-ANALYSIS.md
  2. CLAUDE.md Updated: Added Technical Debt section
  3. Status.md Updated: This entry

📋 PREVIOUS SESSION - SCHEDULED SYNC PERSISTENCE FIX (Dec 20, 2025)

Status: COMPLETE - Deployed to Production

Problem: Scheduled sync showed "Not Scheduled" after page refresh, even though settings were saved correctly.

Root Cause:

  • HVAC_Zoho_Scheduled_Sync was only loaded in admin context
  • On non-admin requests (including WP-Cron), custom cron schedules weren't registered
  • WordPress was clearing cron events because it didn't recognize the schedules

Fixes Applied

  1. Load Scheduled Sync on ALL Requests (class-hvac-plugin.php)

    • Moved HVAC_Zoho_Scheduled_Sync::instance() initialization to main plugin loader
    • Now loads alongside other schedulers (like Communication Scheduler)
    • Ensures cron schedules and action hooks are always registered
  2. Add add_option Hook (class-zoho-scheduled-sync.php)

    • Added add_option_hvac_zoho_auto_sync hook for first-time setting creation
    • WordPress fires add_option_ (not update_option_) on first save
  3. Explicit Scheduling in Save (class-zoho-admin.php)

    • save_settings() now explicitly calls schedule_sync() or unschedule_sync()
    • Ensures scheduling works even when option value hasn't changed
    • update_option_ hook only fires when value actually changes

Files Modified

  • includes/class-hvac-plugin.php - Load scheduled sync globally
  • includes/zoho/class-zoho-scheduled-sync.php - Add first-time option hook
  • includes/admin/class-zoho-admin.php - Explicit scheduling call

📋 PREVIOUS SESSION - PUBLIC MAP & DIRECTORY FIX (Dec 21, 2025)

Status: 🔄 IN PROGRESS - Deployed to Staging (Strategy H)

Problem: Map markers missing. Data analysis reveals markers have identical Latitude and Longitude values (corruption).

Root Cause:

  • IGM Plugin's client-side processing corrupts longitude by overwriting it with latitude immediately before rendering.
  • Previous PHP Injection strategies (D-G) caused 500 errors due to WP_Query timing/context issues in the footer.

Solution (Strategy H):

  1. Javascript Interceptor: Injected a robust interceptor script in class-hvac-mapgeo-integration.php.
  2. Mechanism: Uses Object.defineProperty on window.iMapsData to catch the data assignment before the map plugin sees it.
  3. Repair Logic: Detects corrupted markers (Lat == Lng) and instantly restores correct values from safe lat/lng backup keys provided by PHP.
  4. Cleanup: Removed dangerous PHP query injections that were causing server errors.

Current Status:

  • Fix deployed to Staging.
  • Pending verification of visible markers and "Healed" console logs.

Next Steps:

  1. Verify map renders correctly on Staging.
  2. Deploy to Production.

📋 PREVIOUS SESSION - SCHEDULED ZOHO SYNC (Dec 19, 2025)

Status: COMPLETE - WP-Cron Scheduled Sync Implemented

Summary:

  • Scheduled Sync: WP-Cron job syncs new/modified records on configurable interval
  • Incremental Sync: Only syncs records modified since last sync run
  • Admin UI: Enable/disable toggle, interval selector (5min-daily), status display
  • Manual Trigger: "Run Sync Now" button for testing

Changes Made

  1. New File: class-zoho-scheduled-sync.php

    • WP-Cron management with custom intervals
    • run_scheduled_sync() processes all data types
    • Tracks last sync time for incremental filtering
    • Stores results for status display
  2. Updated class-zoho-sync.php

    • All 5 sync methods now accept $since_timestamp parameter
    • When provided, filters queries by post_modified >= since_date
  3. Updated class-zoho-admin.php

    • Added save_settings() AJAX handler
    • Added run_scheduled_sync_now() AJAX handler
    • Enhanced admin UI with new intervals and status display
  4. Updated zoho-admin.js

    • Settings form reloads page on save
    • "Run Sync Now" button with result display

Interval Options

Value Frequency
every_5_minutes Every 5 minutes (default)
every_15_minutes Every 15 minutes
every_30_minutes Every 30 minutes
hourly Hourly
every_6_hours Every 6 hours
daily Daily

Admin Page Location

  • /wp-admin/admin.php?page=hvac-zoho-sync
  • Look for "Scheduled Sync Settings" section

📋 PREVIOUS SESSION - BATCH SYNC ENHANCEMENT (Dec 18, 2025)

Status: COMPLETE - All Sync Tasks Now Auto-Iterate with Progress Bar

Summary:

  • All 5 Sync Types: Now support batch pagination with auto-continue
  • Progress Bar: Visual feedback showing X of Y processed (N%)
  • No Manual Repeating: Frontend auto-loops until has_more: false
  • Orphan Cleanup: Deleted 14 test attendees referencing deleted events

Changes Made

  1. Backend Pagination:
    • All sync methods (sync_events, sync_users, sync_attendees, sync_rsvps, sync_purchases) now accept $offset and $limit parameters
    • Each returns has_more, next_offset, and total for pagination
    • Admin endpoint updated to pass offset to sync methods
  2. Frontend Progress UI:
    • New syncWithProgress() function replaces single AJAX calls
    • Auto-continues batches until complete
    • Progress bar shows percentage and count
    • Accumulated results across all batches

Files Modified

  • includes/zoho/class-zoho-sync.php - Pagination for all 5 sync methods
  • includes/admin/class-zoho-admin.php - Offset parameter handling
  • assets/js/zoho-admin.js - Progress bar + auto-continue logic

📋 PREVIOUS SESSION - ZOHO CRM ATTENDEE SYNC (Dec 17-18, 2025)

Status: COMPLETE - All Attendees Syncing Successfully

Summary:

  • Events Sync: WORKING. 39 events synced with enhanced field mapping.
  • Attendees Sync: WORKING. 50/50 synced, 0 errors, all contacts updated with custom fields.

Issues Resolved

  1. Campaign Member Linking:
    • Fixed API endpoint: PUT /Contacts/{id}/Campaigns (was /Campaigns/{id}/Contacts/{id})
    • Fixed log_debug() visibility (private → public)
  2. Attendee Field Mapping:
    • measureQuick Email → Email (primary, used for lookup)
    • Attendee Email → Secondary_Email
    • Attendee Cell Phone → Mobile
    • Company Role → Primary_Role
    • Fixed meta key: _tec_tickets_commerce_attendee_fields with hyphenated field names
  3. Email Fallback Logic:
    • If attendee email empty, use measureQuick email (and vice versa)
    • Only fails if BOTH emails are empty
  4. DUPLICATE_DATA Handling:
    • When Zoho returns "duplicate exists", extract existing contact ID from error
    • Use that ID to update instead of failing
  5. Existing Contact Updates:
    • Existing contacts now updated via PUT with new field data on each sync

Zoho CRM Integration - Staging Environment (Working)

Status: OAuth Working, Sync Methods Implemented, Dry-Run Tested

Completed:

  1. OAuth Authentication Verified

    • Refresh token exists and is valid
    • API connection successful (53 modules accessible)
    • Read operations working (Contacts, Campaigns, Users)
  2. Read-Only API Tests Passed

    • Organization Info: Manifold Cloud Services (America/Detroit)
    • Contacts: 5+ records readable (Tanner Moore, Pete Knochelmann, etc.)
    • Campaigns: 5+ records readable (Nov 28, Oct 23, etc.)
    • CRM Users: Ben Reed (CEO), JR Lawhorne (Manager), etc.
  3. Sync Class Bug Fixes

    • Fixed user roles: trainer/traineehvac_trainer/hvac_master_trainer
    • Fixed event filter: Removed restrictive _hvac_event_type meta query
    • Fixed event display: Changed eventDisplay from list to custom to include past events
    • Fixed WooCommerce dependency: Added graceful error handling
  4. Event Tickets Integration (NEW)

    • Replaced WooCommerce sync with Event Tickets (Tickets Commerce) support
    • Added sync_attendees() method → Zoho Contacts + Campaign Members
    • Added sync_rsvps() method → Zoho Leads + Campaign Members
    • Updated meta keys for Tickets Commerce (_tec_tickets_commerce_*)
    • Updated meta keys for RSVPs (_tribe_rsvp_*)
  5. Admin Interface Updated

    • Added "Sync Attendees" button (Contacts + Campaign Members)
    • Added "Sync RSVPs" button (Leads + Campaign Members)
    • Renamed "Sync Purchases" to "Sync Orders" (Tickets Commerce)

Dry-Run Results (Staging - No Data Sent to Zoho):

Sync Type Records Found Status
Events → Campaigns 20 Ready
Trainers → Contacts 53 Ready
Attendees → Contacts + Campaign Members 79 Ready
RSVPs → Leads + Campaign Members 4 Ready
Orders → Invoices 52 Ready

Zoho CRM Mapping Strategy:

  • EventsCampaigns (direct mapping)
  • Trainers (hvac_trainer, hvac_master_trainer) → Contacts (with Contact_Type field)
  • Ticket AttendeesContacts + Campaign Members (links Contact ↔ Campaign)
  • RSVPsLeads + Campaign Members (links Lead ↔ Campaign)
  • Ticket OrdersInvoices (financial records)

Staging Protection Active:

  • All write operations (POST/PUT/DELETE) are blocked on staging
  • Only production (upskillhvac.com) can write to Zoho CRM
  • Dry-run shows what would sync without actually sending data

Admin Page Location:

  • /wp-admin/admin.php?page=hvac-zoho-sync

Files Modified:

  • includes/zoho/class-zoho-sync.php - Complete rewrite for Event Tickets
  • includes/admin/class-zoho-admin.php - Added new sync buttons

📅 PREVIOUS SESSION - GEMINI TRANSITION & VALIDATION (Dec 16, 2025)

Gemini Development Environment Setup

Objective: Transition from Claude Code-specific tooling to Gemini/Antigravity agent development workflow.

Completed:

  1. Created GEMINI.md - New development guidelines

    • Critical safety constraints for Cloudways Shared VPS
    • Workflows for testing (/test) and deployment
    • Coding standards (Singleton pattern, security, PHP 8+ modernization)
    • Agent personas (Tester, Security Auditor, Deployment Engineer)
  2. Environment Configuration

    • Updated .gitignore to allow .agent/, .mcp.json, GEMINI.md
    • Created /home/ben/dev/upskill-event-manager/.agent/workflows/test.md
    • Fixed file access blocked by gitignore
  3. PHP 8+ Compatibility Verification

    • Issue: true|\WP_Error syntax causing PHP fatal errors on staging (PHP 8.0)
    • Fix: Changed to bool|\WP_Error in includes/class-hvac-security-helpers.php:231
    • Status: Deployed to staging, verified working
  4. Comprehensive Test Suite

    • File: test-comprehensive-validation.js (Playwright E2E tests)
    • Fixed: Login form selectors (#user_login, #user_pass, #wp-submit)
    • Modes: Headless (default) or headed (DISPLAY=:1 HEADLESS=false)
    • Results:
      • Master Trainer pages: ALL PASSING (4/4)
      • Security endpoints: ALL SECURE (4/4)
      • Trainer pages: ⚠️ Require authentication (expected)

Test Results Summary:

✅ Master Dashboard - Functional with navigation
✅ Announcements - Fully functional & responsive
✅ Pending Approvals - Fully functional & responsive
✅ Trainers - Fully functional & responsive

🔒 Security: All AJAX endpoints properly secured (401/400 responses)
   - hvac_get_trainer_stats
   - hvac_manage_announcement
   - hvac_approve_trainer
   - hvac_approve_trainer_v2

Test Credentials Updated:

  • test_master / Test123! (hvac_master_trainer)
  • test_trainer / Test123! (hvac_trainer)
  • test_admin / Test123! (administrator)
  1. Master Trainer Navigation Dropdown Fix (Dec 16, 2025)
    • Issue: Green/teal colored boxes appearing in navigation toolbar instead of dropdown arrows
    • Root Cause: Empty <span class="menu-toggle"> elements with CSS background styling
    • Fix: Replaced with <span class="dropdown-arrow">▼</span> in includes/class-hvac-master-menu-system.php:327
    • Impact: All master trainer pages (/master-trainer/*)
    • Status: Deployed to staging, verified working
    • Verification: Screenshots confirm dropdown arrows display correctly, green boxes removed

📁 RECENT DEPLOYMENTS

v2.1.7 - Critical Nonce Fix (Nov 3, 2025)

Issue: Announcement submission completely broken - nonce mismatch
Fix: Changed nonce action from hvac_announcements_admin_noncehvac_announcements_nonce
Files: includes/class-hvac-announcements-admin.php (line 96)
Status: Deployed to staging, fully functional

v2.1.6 - Technical Debt Cleanup

Fixes:

  1. Version synchronization (2.0.0 → 2.1.6 in plugin header)
  2. FOUC prevention (modal display: none by default)
  3. Conditional logging (error_log()HVAC_Logger::log())

v2.1.5 - Z-Index Stacking Fix

Issue: WordPress media modal appearing behind announcement modal
Fix: Reduced announcement modal z-index from 999999 → 100000
Result: Media modals (z-index 160000) now properly stack on top


🧪 TESTING INFRASTRUCTURE

Comprehensive Test Suite

File: test-comprehensive-validation.js
Framework: Playwright (Node.js)

Run Tests:

# Headless (default)
node test-comprehensive-validation.js

# Headed mode (visible browser)
DISPLAY=:1 HEADLESS=false node test-comprehensive-validation.js

Test Coverage:

  • Trainer pages (4 pages)
  • Master trainer pages (4 pages)
  • Security/AJAX endpoints (4 endpoints)
  • Layout & responsive design
  • Authentication flows

🚀 DEPLOYMENT

Staging Environment

URL: https://upskill-staging.measurequick.com
Version: 2.1.7 + PHP 8+ fixes
Server: Cloudways Shared VPS (PHP 8.0)
Status: Fully functional

Deploy to Staging:

./scripts/deploy.sh staging

Verify Deployment:

./scripts/verify-plugin-fixes.sh

Production Environment

URL: https://upskillhvac.com
Version: 2.1.8 (latest)
Server: Cloudways Shared VPS


🔧 KEY DEVELOPMENT GUIDELINES

GEMINI.md Rules (NEW)

  1. Safety First:

    • NEVER delete files outside project directory
    • NEVER execute rm -rf without confirmation
    • NEVER modify system configs (/etc/*, /var/*)
    • NEVER deploy to production without explicit request
  2. Infrastructure Constraints:

    • Cloudways Shared VPS (limited resources)
    • Do NOT force PHP version changes
    • Do NOT install system-level packages
    • Be mindful of CPU/RAM usage
  3. Testing Mandatory:

    node test-comprehensive-validation.js
    
  4. Security Standards:

    • Always sanitize input
    • Always escape output
    • Verify nonces on forms & AJAX
    • Check roles/capabilities

WordPress Architecture

  • Singleton Pattern: All core classes use ::instance()
  • Template Security: All templates start with security check
  • PHP 8+ Modernization: In progress (avoid PHP 8.2+ features)

📚 DOCUMENTATION

Primary Files

  • GEMINI.md - Gemini agent development guidelines (NEW)
  • CLAUDE.md - Claude Code agent guidelines (legacy)
  • docs/ARCHITECTURE.md - Plugin architecture details
  • docs/CLAUDE-CODE-DEVELOPMENT-BEST-PRACTICES.md - Development patterns

Workflows

  • .agent/workflows/test.md - Running comprehensive tests (/test)

📋 NEXT ACTIONS

Immediate

  1. Production Deployment - Deploy v2.1.7 + PHP 8+ fixes (pending user approval)
  2. PHP 8+ Modernization - Continue Phase 2 modernization
  3. 🔜 Enhancements - New features for next session

Pre-Production Checklist

  • PHP 8+ compatibility verified
  • Security endpoints validated
  • Master trainer pages functional
  • Comprehensive tests passing
  • No fatal errors on staging

Deploy Command:

./scripts/deploy.sh production

⚠️ KNOWN ISSUES

Minor (Non-Blocking)

  1. Playwright Headless Login - Works in headed mode with correct selectors
  2. jQuery Loading Timing - Brief "jQuery is not defined" error (non-blocking)
  3. Dashboard Responsive - Minor responsive layout issue (cosmetic)

📊 SUMMARY

Current State: PRODUCTION READY

Key Achievements:

  • Gemini development environment established
  • PHP 8+ compatibility verified and deployed
  • Comprehensive test suite functional (headed mode)
  • All security endpoints properly secured
  • Master trainer features fully operational
  • Test accounts updated and working

Quality Metrics:

  • Test Coverage: 8 pages + 4 security endpoints
  • Success Rate: 100% master trainer pages
  • Security: 100% endpoints secured
  • PHP Compatibility: No fatal errors

Agent Transition:

  • From: Claude Code + MCP tools
  • To: Gemini/Antigravity + direct tooling
  • Status: Complete and validated

For detailed historical context, see git history and previous Status.md versions