Compare commits
No commits in common. "1526d9f23b5b26741e5d7a642d2642db5c614415" and "6d4bdc2f95500faa4800276e31437115e8bf060c" have entirely different histories.
1526d9f23b
...
6d4bdc2f95
10 changed files with 581 additions and 1357 deletions
|
|
@ -2,46 +2,44 @@
|
||||||
"$schema": "https://json.schemastore.org/claude-code-settings.json",
|
"$schema": "https://json.schemastore.org/claude-code-settings.json",
|
||||||
"permissions": {
|
"permissions": {
|
||||||
"allow": [
|
"allow": [
|
||||||
"Bash(SSHPASS=\"uSCO6f1y\" sshpass -e ssh -o StrictHostKeyChecking=no roodev@146.190.76.204 \"cd /home/974670.cloudwaysapps.com/uberrxmprk/public_html && wp post get 5346 --fields=ID,post_title,post_name\")",
|
"Bash(SSHPASS=\"uSCO6f1y\" sshpass -e ssh -o StrictHostKeyChecking=no roodev@146.190.76.204 \"tail -100 /home/974670.cloudwaysapps.com/uberrxmprk/public_html/wp-content/debug.log | grep -i -E ''(fatal|error|warning|dashboard|manage)''\")",
|
||||||
"Bash(SSHPASS=\"uSCO6f1y\" sshpass -e ssh -o StrictHostKeyChecking=no roodev@146.190.76.204 \"tail -30 /home/974670.cloudwaysapps.com/uberrxmprk/public_html/wp-content/debug.log | grep -i ''hvac announcements admin''\")",
|
"Bash(SSHPASS=\"uSCO6f1y\" sshpass -e ssh -o StrictHostKeyChecking=no roodev@146.190.76.204 \"cd /home/974670.cloudwaysapps.com/uberrxmprk/public_html && wp plugin list | grep -E ''(events-calendar|tribe)''\")",
|
||||||
"mcp__playwright__browser_navigate",
|
"Bash(SSHPASS=\"uSCO6f1y\" sshpass -e ssh -o StrictHostKeyChecking=no roodev@146.190.76.204 \"cd /home/974670.cloudwaysapps.com/uberrxmprk/public_html && wp plugin deactivate the-events-calendar-community-events\")",
|
||||||
"mcp__playwright__browser_evaluate",
|
"Bash(printf:*)",
|
||||||
"Bash(SSHPASS=\"uSCO6f1y\" sshpass -e ssh -o StrictHostKeyChecking=no roodev@146.190.76.204 \"tail -200 /home/974670.cloudwaysapps.com/uberrxmprk/public_html/wp-content/debug.log | grep -i ''enqueue''\")",
|
"Bash(SSHPASS=\"uSCO6f1y\" sshpass -e ssh -o StrictHostKeyChecking=no benr@146.190.76.204 \"tail -100 /home/974670.cloudwaysapps.com/ncjzsayvsk/public_html/wp-content/debug.log | grep -i -E ''(security|nonce|edit|6288)''\")",
|
||||||
"Bash(SSHPASS=\"uSCO6f1y\" sshpass -e ssh -o StrictHostKeyChecking=no roodev@146.190.76.204 \"tail -300 /home/974670.cloudwaysapps.com/uberrxmprk/public_html/wp-content/debug.log | grep -i -E ''(wp_enqueue_scripts|init_hooks)''\")",
|
|
||||||
"Bash(scripts/deploy.sh:*)",
|
"Bash(scripts/deploy.sh:*)",
|
||||||
"Bash(SSHPASS=\"uSCO6f1y\" sshpass -e ssh -o StrictHostKeyChecking=no roodev@146.190.76.204 \"tail -100 /home/974670.cloudwaysapps.com/uberrxmprk/public_html/wp-content/debug.log | grep -i ''HVAC_Announcements_Admin''\")",
|
"mcp__playwright__browser_navigate",
|
||||||
"Bash(SSHPASS=\"uSCO6f1y\" sshpass -e ssh -o StrictHostKeyChecking=no roodev@146.190.76.204 \"tail -150 /home/974670.cloudwaysapps.com/uberrxmprk/public_html/wp-content/debug.log | grep -i ''HVAC_Announcements_Admin''\")",
|
"Bash(SSHPASS=\"uSCO6f1y\" sshpass -e ssh -o StrictHostKeyChecking=no roodev@146.190.76.204 \"cd /home/974670.cloudwaysapps.com/uberrxmprk/public_html && wp user list --role=hvac_master_trainer --fields=user_login,user_email --format=table\")",
|
||||||
"Bash(SSHPASS=\"uSCO6f1y\" sshpass -e ssh -o StrictHostKeyChecking=no roodev@146.190.76.204 \"tail -200 /home/974670.cloudwaysapps.com/uberrxmprk/public_html/wp-content/debug.log\")",
|
|
||||||
"Bash(SSHPASS=\"uSCO6f1y\" sshpass -e ssh -o StrictHostKeyChecking=no roodev@146.190.76.204 \"cd /home/974670.cloudwaysapps.com/uberrxmprk/public_html && wp cache flush\")",
|
|
||||||
"Bash(SSHPASS=\"uSCO6f1y\" sshpass -e ssh -o StrictHostKeyChecking=no roodev@146.190.76.204 \"tail -50 /home/974670.cloudwaysapps.com/uberrxmprk/public_html/wp-content/debug.log | grep -i ''HVAC''\")",
|
|
||||||
"Bash(SSHPASS=\"uSCO6f1y\" sshpass -e ssh -o StrictHostKeyChecking=no roodev@146.190.76.204 \"tail -200 /home/974670.cloudwaysapps.com/uberrxmprk/public_html/wp-content/debug.log | grep -A5 ''HVAC_Announcements_Admin.*enqueue_admin_assets called''\")",
|
|
||||||
"Bash(SSHPASS=\"uSCO6f1y\" sshpass -e ssh -o StrictHostKeyChecking=no roodev@146.190.76.204 \"tail -500 /home/974670.cloudwaysapps.com/uberrxmprk/public_html/wp-content/debug.log | grep -i ''enqueue.*admin.*assets\\|ENQUEUING SCRIPTS''\")",
|
|
||||||
"mcp__zen__debug",
|
|
||||||
"Bash(SSHPASS=\"uSCO6f1y\" sshpass -e ssh -o StrictHostKeyChecking=no roodev@146.190.76.204 \"cd /home/974670.cloudwaysapps.com/uberrxmprk/public_html && wp user get 25 --field=roles\")",
|
|
||||||
"WebSearch",
|
|
||||||
"mcp__zen__chat",
|
|
||||||
"mcp__playwright__browser_click",
|
|
||||||
"mcp__playwright__browser_take_screenshot",
|
|
||||||
"Bash(SSHPASS=\"uSCO6f1y\" sshpass -e ssh -o StrictHostKeyChecking=no roodev@146.190.76.204 \"grep -A5 ''wp_enqueue_script.*hvac-announcements-admin'' /home/974670.cloudwaysapps.com/uberrxmprk/public_html/wp-content/plugins/hvac-community-events/includes/class-hvac-announcements-admin.php | head -20\")",
|
|
||||||
"mcp__zen__analyze",
|
|
||||||
"mcp__playwright__browser_type",
|
"mcp__playwright__browser_type",
|
||||||
"mcp__playwright__browser_close",
|
"mcp__playwright__browser_click",
|
||||||
"mcp__playwright__browser_install",
|
"Bash(SSHPASS=\"uSCO6f1y\" sshpass -e ssh -o StrictHostKeyChecking=no roodev@146.190.76.204 \"cd /home/974670.cloudwaysapps.com/uberrxmprk/public_html && wp user update joe@upskillhvac.com --user_pass=''JoeTest123!'' --skip-email\")",
|
||||||
"Bash(SSHPASS=\"uSCO6f1y\" sshpass -e ssh -o StrictHostKeyChecking=no roodev@146.190.76.204 \"cd /home/974670.cloudwaysapps.com/uberrxmprk/public_html && wp option get hvac_zoho_client_id 2>/dev/null || echo ''NOT SET''\")",
|
"Bash(SSHPASS=\"uSCO6f1y\" sshpass -e ssh -o StrictHostKeyChecking=no roodev@146.190.76.204 \"cd /home/974670.cloudwaysapps.com/uberrxmprk/public_html && wp user list --role=hvac_trainer --fields=user_login,user_email --format=table | head -5\")",
|
||||||
"Bash(SSHPASS=\"uSCO6f1y\" sshpass -e ssh -o StrictHostKeyChecking=no roodev@146.190.76.204 \"cd /home/974670.cloudwaysapps.com/uberrxmprk/public_html && wp option get hvac_zoho_refresh_token 2>/dev/null || echo ''NOT SET''\")",
|
"Bash(SSHPASS=\"uSCO6f1y\" sshpass -e ssh -o StrictHostKeyChecking=no roodev@146.190.76.204 \"tail -50 /home/974670.cloudwaysapps.com/uberrxmprk/public_html/wp-content/debug.log | grep -i -E ''(master-trainer|trainers|javascript|enqueue)''\")",
|
||||||
"Bash(SSHPASS=\"uSCO6f1y\" sshpass -e ssh -o StrictHostKeyChecking=no roodev@146.190.76.204 \"cd /home/974670.cloudwaysapps.com/uberrxmprk/public_html && wp eval ''\nrequire_once ABSPATH . \"\"wp-content/plugins/hvac-community-events/includes/zoho/class-zoho-crm-auth.php\"\";\n$auth = new HVAC_Zoho_CRM_Auth();\n\necho \"\"=== ZOHO CRM READ-ONLY TEST ===\"\";\necho \"\"\\n\\n1. ORGANIZATION INFO:\\n\"\";\n$org = $auth->make_api_request(\"\"/org\"\", \"\"GET\"\");\nif (isset($org[\"\"org\"\"][0])) {\n $o = $org[\"\"org\"\"][0];\n echo \"\" Company: \"\" . $o[\"\"company_name\"\"] . \"\"\\n\"\";\n echo \"\" Country: \"\" . ($o[\"\"country\"\"] ?? \"\"N/A\"\") . \"\"\\n\"\";\n echo \"\" Time Zone: \"\" . ($o[\"\"time_zone\"\"] ?? \"\"N/A\"\") . \"\"\\n\"\";\n} else {\n echo \"\" Error: \"\" . print_r($org, true);\n}\n''\")",
|
"Bash(SSHPASS=\"uSCO6f1y\" sshpass -e ssh -o StrictHostKeyChecking=no roodev@146.190.76.204 \"cd /home/974670.cloudwaysapps.com/uberrxmprk/public_html && wp user get test_master --field=roles\")",
|
||||||
"Bash(SSHPASS=\"uSCO6f1y\" sshpass -e ssh -o StrictHostKeyChecking=no roodev@146.190.76.204 \"cd /home/974670.cloudwaysapps.com/uberrxmprk/public_html && wp eval ''\nrequire_once ABSPATH . \"\"wp-content/plugins/hvac-community-events/includes/zoho/class-zoho-crm-auth.php\"\";\n$auth = new HVAC_Zoho_CRM_Auth();\n\necho \"\"2. CONTACTS (first 5):\\n\"\";\n$contacts = $auth->make_api_request(\"\"/Contacts?per_page=5\"\", \"\"GET\"\");\nif (isset($contacts[\"\"data\"\"])) {\n foreach ($contacts[\"\"data\"\"] as $c) {\n echo \"\" - \"\" . ($c[\"\"Full_Name\"\"] ?? $c[\"\"Email\"\"] ?? \"\"Unknown\"\") . \"\"\\n\"\";\n }\n echo \"\" Total in response: \"\" . count($contacts[\"\"data\"\"]) . \"\"\\n\"\";\n} elseif (isset($contacts[\"\"info\"\"])) {\n echo \"\" No contacts found (empty CRM)\\n\"\";\n} else {\n echo \"\" Response: \"\" . print_r($contacts, true);\n}\n''\")",
|
"Bash(SSHPASS=\"uSCO6f1y\" sshpass -e ssh -o StrictHostKeyChecking=no roodev@146.190.76.204 \"cd /home/974670.cloudwaysapps.com/uberrxmprk/public_html && wp user create test_master_new test.master.new@example.com --role=hvac_master_trainer --user_pass=''TestNew123!'' --skip-email 2>&1 || wp user update test_master_new --user_pass=''TestNew123!'' --skip-email\")",
|
||||||
"Bash(SSHPASS=\"uSCO6f1y\" sshpass -e ssh -o StrictHostKeyChecking=no roodev@146.190.76.204 \"cd /home/974670.cloudwaysapps.com/uberrxmprk/public_html && wp eval ''\nrequire_once ABSPATH . \"\"wp-content/plugins/hvac-community-events/includes/zoho/class-zoho-crm-auth.php\"\";\n$auth = new HVAC_Zoho_CRM_Auth();\n\necho \"\"3. CAMPAIGNS (first 5):\\n\"\";\n$campaigns = $auth->make_api_request(\"\"/Campaigns?per_page=5\"\", \"\"GET\"\");\nif (isset($campaigns[\"\"data\"\"])) {\n foreach ($campaigns[\"\"data\"\"] as $c) {\n echo \"\" - \"\" . ($c[\"\"Campaign_Name\"\"] ?? \"\"Unnamed\"\") . \"\"\\n\"\";\n }\n} elseif (isset($campaigns[\"\"code\"\"]) && $campaigns[\"\"code\"\"] == \"\"INVALID_MODULE\"\") {\n echo \"\" Campaigns module not enabled\\n\"\";\n} else {\n echo \"\" Response: \"\" . json_encode($campaigns) . \"\"\\n\"\";\n}\n\necho \"\"\\n4. USERS (CRM users):\\n\"\";\n$users = $auth->make_api_request(\"\"/users?type=AllUsers\"\", \"\"GET\"\");\nif (isset($users[\"\"users\"\"])) {\n foreach (array_slice($users[\"\"users\"\"], 0, 5) as $u) {\n echo \"\" - \"\" . $u[\"\"full_name\"\"] . \"\" (\"\" . $u[\"\"role\"\"][\"\"name\"\"] . \"\")\\n\"\";\n }\n} else {\n echo \"\" Response: \"\" . json_encode($users) . \"\"\\n\"\";\n}\n''\")",
|
"Bash(SSHPASS=\"uSCO6f1y\" sshpass -e ssh -o StrictHostKeyChecking=no roodev@146.190.76.204 \"cd /home/974670.cloudwaysapps.com/uberrxmprk/public_html && wp user list --field=user_login | grep test\")",
|
||||||
"Bash(SSHPASS=\"uSCO6f1y\" sshpass -e ssh -o StrictHostKeyChecking=no roodev@146.190.76.204 \"cd /home/974670.cloudwaysapps.com/uberrxmprk/public_html && wp eval ''\necho \"\"=== EVENT TICKETS DATA STRUCTURE ===\"\";\necho \"\"\\n\"\";\n\n// Check what ticket-related post types exist\n$post_types = get_post_types(array(), \"\"names\"\");\n$ticket_types = array_filter($post_types, function($pt) {\n return strpos($pt, \"\"ticket\"\") !== false || strpos($pt, \"\"tec\"\") !== false || strpos($pt, \"\"tribe\"\") !== false || strpos($pt, \"\"attendee\"\") !== false || strpos($pt, \"\"order\"\") !== false;\n});\necho \"\"Ticket-related post types:\\n\"\";\nforeach ($ticket_types as $pt) {\n $count = wp_count_posts($pt);\n $total = isset($count->publish) ? $count->publish : 0;\n echo \"\" - \"\" . $pt . \"\" (\"\" . $total . \"\" published)\\n\"\";\n}\n\necho \"\"\\n\"\";\n\n// Check for Tickets Commerce orders\nif (class_exists(\"\"TEC\\Tickets\\Commerce\\Order\"\")) {\n echo \"\"Tickets Commerce Order class exists\\n\"\";\n}\n\n// Check for attendees\n$attendees = get_posts(array(\n \"\"post_type\"\" => \"\"tribe_tpp_attendees\"\",\n \"\"posts_per_page\"\" => 5,\n \"\"post_status\"\" => \"\"any\"\"\n));\necho \"\"\\nAttendees (tribe_tpp_attendees): \"\" . count($attendees) . \"\"\\n\"\";\n\n// Try tribe_rsvp_attendees\n$rsvp = get_posts(array(\n \"\"post_type\"\" => \"\"tribe_rsvp_attendees\"\", \n \"\"posts_per_page\"\" => 5,\n \"\"post_status\"\" => \"\"any\"\"\n));\necho \"\"RSVPs (tribe_rsvp_attendees): \"\" . count($rsvp) . \"\"\\n\"\";\n\n// Try tec_tc_attendee (Tickets Commerce)\n$tc_attendees = get_posts(array(\n \"\"post_type\"\" => \"\"tec_tc_attendee\"\",\n \"\"posts_per_page\"\" => 5, \n \"\"post_status\"\" => \"\"any\"\"\n));\necho \"\"TC Attendees (tec_tc_attendee): \"\" . count($tc_attendees) . \"\"\\n\"\";\n\n// Try tec_tc_order\n$tc_orders = get_posts(array(\n \"\"post_type\"\" => \"\"tec_tc_order\"\",\n \"\"posts_per_page\"\" => 5,\n \"\"post_status\"\" => \"\"any\"\"\n));\necho \"\"TC Orders (tec_tc_order): \"\" . count($tc_orders) . \"\"\\n\"\";\n''\")",
|
"Bash(SSHPASS=\"uSCO6f1y\" sshpass -e ssh -o StrictHostKeyChecking=no roodev@146.190.76.204 \"cd /home/974670.cloudwaysapps.com/uberrxmprk/public_html && which composer && composer --version\")",
|
||||||
"Bash(SSHPASS=\"uSCO6f1y\" sshpass -e ssh -o StrictHostKeyChecking=no roodev@146.190.76.204 \"cd /home/974670.cloudwaysapps.com/uberrxmprk/public_html && wp eval ''\necho \"\"=== EVENT TICKETS DATA STRUCTURE ===\\n\\n\"\";\n\n// Check ticket-related post types\n$post_types = get_post_types(array(), \"\"names\"\");\necho \"\"Ticket-related post types:\\n\"\";\nforeach ($post_types as $pt) {\n if (strpos($pt, \"\"ticket\"\") !== false || strpos($pt, \"\"attendee\"\") !== false || strpos($pt, \"\"rsvp\"\") !== false || strpos($pt, \"\"tec_tc\"\") !== false) {\n $count = wp_count_posts($pt);\n $total = isset($count->publish) ? $count->publish : 0;\n echo \"\" - \"\" . $pt . \"\" (\"\" . $total . \"\" published)\\n\"\";\n }\n}\n''\")",
|
"Bash(unzip:*)",
|
||||||
"Bash(SSHPASS=\"uSCO6f1y\" sshpass -e ssh -o StrictHostKeyChecking=no roodev@146.190.76.204 'cd /home/974670.cloudwaysapps.com/uberrxmprk/public_html && cat > /tmp/check_orders.php << ''''PHPCODE''''\n<?php\nrequire_once(\"\"wp-load.php\"\");\n\necho \"\"=== TICKETS COMMERCE ORDERS ===\\n\\n\"\";\n\n// Get TC orders\n$orders = get_posts(array(\n \"\"post_type\"\" => \"\"tec_tc_order\"\",\n \"\"posts_per_page\"\" => 3,\n \"\"post_status\"\" => \"\"any\"\"\n));\n\necho \"\"Found \"\" . count($orders) . \"\" sample orders\\n\\n\"\";\n\nforeach ($orders as $order) {\n echo \"\"--- Order #\"\" . $order->ID . \"\" ---\\n\"\";\n echo \"\"Status: \"\" . $order->post_status . \"\"\\n\"\";\n echo \"\"Date: \"\" . $order->post_date . \"\"\\n\"\";\n \n $meta = get_post_meta($order->ID);\n \n // Key fields\n $fields = array(\n \"\"_tec_tc_order_purchaser_name\"\",\n \"\"_tec_tc_order_purchaser_email\"\", \n \"\"_tec_tc_order_total\"\",\n \"\"_tec_tc_order_gateway\"\",\n \"\"_tec_tc_order_gateway_order_id\"\",\n \"\"_tec_tc_order_items\"\"\n );\n \n foreach ($fields as $f) {\n if (isset($meta[$f])) {\n $val = $meta[$f][0];\n if (is_serialized($val)) {\n $val = \"\"SERIALIZED: \"\" . substr($val, 0, 100) . \"\"...\"\";\n }\n echo \"\"$f: $val\\n\"\";\n }\n }\n echo \"\"\\n\"\";\n}\n\n// Also check attendees linked to orders\necho \"\"=== SAMPLE ATTENDEE WITH ORDER LINK ===\\n\"\";\n$attendee = get_posts(array(\n \"\"post_type\"\" => \"\"tec_tc_attendee\"\",\n \"\"posts_per_page\"\" => 1,\n \"\"post_status\"\" => \"\"any\"\"\n));\nif ($attendee) {\n $a = $attendee[0];\n $meta = get_post_meta($a->ID);\n echo \"\"Attendee ID: \"\" . $a->ID . \"\"\\n\"\";\n echo \"\"Event ID: \"\" . ($meta[\"\"_tec_tc_attendee_event\"\"][0] ?? \"\"N/A\"\") . \"\"\\n\"\";\n echo \"\"Order ID: \"\" . ($meta[\"\"_tec_tc_order\"\"][0] ?? $meta[\"\"_tribe_tpp_order\"\"][0] ?? \"\"N/A\"\") . \"\"\\n\"\";\n echo \"\"Ticket ID: \"\" . ($meta[\"\"_tec_tc_attendee_ticket\"\"][0] ?? \"\"N/A\"\") . \"\"\\n\"\";\n echo \"\"Name: \"\" . ($meta[\"\"_tec_tc_attendee_name\"\"][0] ?? $meta[\"\"_tribe_tickets_full_name\"\"][0] ?? \"\"N/A\"\") . \"\"\\n\"\";\n echo \"\"Email: \"\" . ($meta[\"\"_tec_tc_attendee_email\"\"][0] ?? $meta[\"\"_tribe_tickets_email\"\"][0] ?? \"\"N/A\"\") . \"\"\\n\"\";\n}\nPHPCODE\nphp /tmp/check_orders.php')",
|
"Bash(SSHPASS=\"uSCO6f1y\" sshpass -e ssh -o StrictHostKeyChecking=no roodev@146.190.76.204 \"cd /home/974670.cloudwaysapps.com/uberrxmprk/public_html && wp plugin list | grep -E ''(wordpress-mcp|Name)''\")",
|
||||||
"Bash(SSHPASS=\"uSCO6f1y\" sshpass -e ssh -o StrictHostKeyChecking=no roodev@146.190.76.204 'cd /home/974670.cloudwaysapps.com/uberrxmprk/public_html && cat > /tmp/test_sync.php << ''''PHPCODE''''\n<?php\nrequire_once(\"\"wp-load.php\"\");\nrequire_once(ABSPATH . \"\"wp-content/plugins/hvac-community-events/includes/zoho/class-zoho-sync.php\"\");\n\n$sync = new HVAC_Zoho_Sync();\n\necho \"\"=== DRY-RUN: ALL SYNC TYPES ===\\n\\n\"\";\n\n// 1. Events\necho \"\"1. EVENTS → CAMPAIGNS\\n\"\";\n$result = $sync->sync_events();\necho \"\" Total: \"\" . $result[\"\"total\"\"] . \"\", Would Sync: \"\" . $result[\"\"synced\"\"] . \"\"\\n\"\";\nif (!empty($result[\"\"test_data\"\"])) {\n $sample = $result[\"\"test_data\"\"][0];\n echo \"\" Sample: \"\" . substr($sample[\"\"event_title\"\"], 0, 40) . \"\"...\\n\"\";\n}\necho \"\"\\n\"\";\n\n// 2. Users (Trainers)\necho \"\"2. TRAINERS → CONTACTS\\n\"\";\n$result = $sync->sync_users();\necho \"\" Total: \"\" . $result[\"\"total\"\"] . \"\", Would Sync: \"\" . $result[\"\"synced\"\"] . \"\"\\n\"\";\nif (!empty($result[\"\"test_data\"\"])) {\n $sample = $result[\"\"test_data\"\"][0];\n echo \"\" Sample: \"\" . $sample[\"\"user_email\"\"] . \"\" (\"\" . $sample[\"\"user_role\"\"] . \"\")\\n\"\";\n}\necho \"\"\\n\"\";\n\n// 3. Attendees\necho \"\"3. ATTENDEES → CONTACTS + CAMPAIGN MEMBERS\\n\"\";\n$result = $sync->sync_attendees();\necho \"\" Total: \"\" . $result[\"\"total\"\"] . \"\", Would Sync: \"\" . $result[\"\"synced\"\"] . \"\"\\n\"\";\nif (!empty($result[\"\"test_data\"\"])) {\n $sample = $result[\"\"test_data\"\"][0];\n echo \"\" Sample: \"\" . ($sample[\"\"full_name\"\"] ?: \"\"Unknown\"\") . \"\" <\"\" . ($sample[\"\"email\"\"] ?: \"\"no-email\"\") . \"\">\\n\"\";\n echo \"\" Event: \"\" . ($sample[\"\"event_title\"\"] ?: \"\"N/A\"\") . \"\"\\n\"\";\n}\necho \"\"\\n\"\";\n\n// 4. RSVPs\necho \"\"4. RSVPs → LEADS + CAMPAIGN MEMBERS\\n\"\";\n$result = $sync->sync_rsvps();\necho \"\" Total: \"\" . $result[\"\"total\"\"] . \"\", Would Sync: \"\" . $result[\"\"synced\"\"] . \"\"\\n\"\";\nif (!empty($result[\"\"test_data\"\"])) {\n $sample = $result[\"\"test_data\"\"][0];\n echo \"\" Sample: \"\" . ($sample[\"\"full_name\"\"] ?: \"\"Unknown\"\") . \"\" <\"\" . ($sample[\"\"email\"\"] ?: \"\"no-email\"\") . \"\">\\n\"\";\n echo \"\" RSVP Status: \"\" . ($sample[\"\"rsvp_status\"\"] ?: \"\"N/A\"\") . \"\"\\n\"\";\n}\necho \"\"\\n\"\";\n\n// 5. Purchases/Orders\necho \"\"5. TICKET ORDERS → INVOICES\\n\"\";\n$result = $sync->sync_purchases();\necho \"\" Total: \"\" . $result[\"\"total\"\"] . \"\", Would Sync: \"\" . $result[\"\"synced\"\"] . \"\"\\n\"\";\nif (!empty($result[\"\"test_data\"\"])) {\n $sample = $result[\"\"test_data\"\"][0];\n echo \"\" Sample: Order #\"\" . $sample[\"\"order_id\"\"] . \"\" - \"\" . $sample[\"\"purchaser_email\"\"] . \"\"\\n\"\";\n echo \"\" Gateway: \"\" . $sample[\"\"gateway\"\"] . \"\", Date: \"\" . $sample[\"\"date\"\"] . \"\"\\n\"\";\n}\necho \"\"\\n\"\";\n\necho \"\"=== ALL SYNCS IN STAGING MODE (NO DATA SENT TO ZOHO) ===\\n\"\";\nPHPCODE\nphp /tmp/test_sync.php')",
|
"WebFetch(domain:github.com)",
|
||||||
"Bash(SSHPASS=\"uSCO6f1y\" sshpass -e ssh -o StrictHostKeyChecking=no roodev@146.190.76.204 'tail -50 /home/974670.cloudwaysapps.com/uberrxmprk/public_html/wp-content/debug.log 2>/dev/null | grep -i \"\"zoho\\|fatal\\|error\"\" | tail -20')",
|
"WebFetch(domain:json.schemastore.org)",
|
||||||
"Bash(./scripts/deploy.sh:*)",
|
"WebFetch(domain:www.schemastore.org)",
|
||||||
"Bash(SSHPASS=\"uSCO6f1y\" sshpass -e ssh -o StrictHostKeyChecking=no roodev@146.190.76.204 'ls -la /home/974670.cloudwaysapps.com/uberrxmprk/public_html/wp-content/plugins/hvac-community-events/assets/css/zoho-admin.css 2>/dev/null || echo \"\"File does not exist on staging\"\"')",
|
"Bash(SSHPASS=\"uSCO6f1y\" sshpass:*)",
|
||||||
"Bash(SSHPASS=\"uSCO6f1y\" sshpass -e ssh -o StrictHostKeyChecking=no roodev@146.190.76.204 'curl -s \"\"https://upskill-staging.measurequick.com/master-trainer/master-dashboard/\"\" 2>/dev/null | sed -n \"\"220,235p\"\"')",
|
"Bash(SSHPASS=\"uSCO6f1y\" sshpass -e scp -o StrictHostKeyChecking=no /tmp/wordpress-mcp.zip roodev@146.190.76.204:/tmp/wordpress-mcp-prod.zip)",
|
||||||
"Bash(curl:*)",
|
"Bash(SSHPASS=\"uSCO6f1y\" sshpass -e ssh -o StrictHostKeyChecking=no roodev@146.190.76.204 \"cd /home/974670.cloudwaysapps.com/ncjzsayvsk/public_html && wp plugin install /tmp/wordpress-mcp-prod.zip --activate\")",
|
||||||
"Bash(yes:*)"
|
"Bash(SSHPASS=\"uSCO6f1y\" sshpass -e ssh -o StrictHostKeyChecking=no benr@146.190.76.204 \"ls -la /home/974670.cloudwaysapps.com/ | head -20\")",
|
||||||
|
"Bash(SSHPASS=\"uSCO6f1y\" sshpass -e ssh -o StrictHostKeyChecking=no roodev@146.190.76.204 \"cat /home/974670.cloudwaysapps.com/ncjzsayvsk/public_html/wp-config.php 2>&1 | grep -i ''site.*url'' | head -5 || echo ''Checking domain...''\")",
|
||||||
|
"Bash(SSHPASS=\"uSCO6f1y@1oVkz0M\" sshpass -e ssh -o StrictHostKeyChecking=no benr@146.190.76.204 \"cd /home/974670.cloudwaysapps.com/ncjzsayvsk/public_html && wp plugin install /tmp/wordpress-mcp-prod.zip --activate\")",
|
||||||
|
"Bash(SSHPASS=\"uSCO6f1y@1oVkz0M\" sshpass -e ssh -o StrictHostKeyChecking=no benr@146.190.76.204 \"cd /home/974670.cloudwaysapps.com/ncjzsayvsk/public_html && wp plugin list | grep -E ''(wordpress-mcp|Name)''\")",
|
||||||
|
"Bash(SSHPASS=\"uSCO6f1y\" sshpass -e ssh -o StrictHostKeyChecking=no roodev@146.190.76.204 \"cd /home/974670.cloudwaysapps.com/uberrxmprk/public_html && wp user update master_trainer --user_pass=''MasterTest123!'' --skip-email 2>&1 || echo ''User does not exist, creating...'' && wp user create master_trainer master_trainer@example.com --role=hvac_master_trainer --user_pass=''MasterTest123!'' --skip-email\")",
|
||||||
|
"Bash(SSHPASS=\"uSCO6f1y\" sshpass -e ssh -o StrictHostKeyChecking=no roodev@146.190.76.204 \"cd /home/974670.cloudwaysapps.com/uberrxmprk/public_html && wp plugin list | grep -E ''(security|login|limit)''\")",
|
||||||
|
"Bash(SSHPASS=\"uSCO6f1y\" sshpass -e ssh -o StrictHostKeyChecking=no roodev@146.190.76.204 \"cd /home/974670.cloudwaysapps.com/uberrxmprk/public_html && wp post list --post_type=page --s=''announcements'' --fields=ID,post_title,post_name,post_status --format=table\")",
|
||||||
|
"mcp__zen__codereview",
|
||||||
|
"mcp__playwright__browser_console_messages",
|
||||||
|
"mcp__zen__debug",
|
||||||
|
"mcp__playwright__browser_evaluate",
|
||||||
|
"mcp__playwright__browser_take_screenshot",
|
||||||
|
"mcp__playwright__browser_wait_for"
|
||||||
],
|
],
|
||||||
"deny": [],
|
"deny": [],
|
||||||
"ask": [],
|
"ask": [],
|
||||||
|
|
|
||||||
23
Status.md
23
Status.md
|
|
@ -39,29 +39,6 @@
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 🎯 CURRENT SESSION - PUBLIC MAP & DIRECTORY FIX (Dec 20, 2025)
|
|
||||||
|
|
||||||
### Status: 🚧 **IN PROGRESS (Debugging)**
|
|
||||||
|
|
||||||
**Problem:** "Find a Trainer" map loads briefly then disappears, replaced by "Map Temporarily Unavailable". Directory filters working but map unstable.
|
|
||||||
|
|
||||||
**Findings:**
|
|
||||||
1. **Safari Blocker Bug:** Identified and fixed `HVAC_Find_Trainer_Assets` correctly blocking assets on Safari.
|
|
||||||
2. **Safety Script Race Condition:** `mapgeo-safety.js` has a hard 6-second timeout loop that conflicts with slower resource loading.
|
|
||||||
3. **Stale Cache Issue:** Browser continues to serve old `mapgeo-safety.js` (6s timeout) despite file update (30s timeout) and version bump (`.fix1`).
|
|
||||||
4. **Environment Constraints:** `wp cache flush` failed (command not found), indicating potential restriction on direct WP-CLI use.
|
|
||||||
|
|
||||||
**Fixes Applied (Pending Verification):**
|
|
||||||
1. ✅ **Removed Safari Blocker:** Corrected logic in `class-hvac-find-trainer-assets.php`.
|
|
||||||
2. ✅ **Increased Timeouts:** Updated `assets/js/mapgeo-safety.js` to 30s global timeout.
|
|
||||||
3. ✅ **Version Bump:** Added `.fix1` suffix to enqueue version in `class-hvac-mapgeo-safety.php`.
|
|
||||||
|
|
||||||
**Next Steps:**
|
|
||||||
- Resolve caching issue to ensure updated `mapgeo-safety.js` is served.
|
|
||||||
- Verify map stability with 30s timeout.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 📋 PREVIOUS SESSION - SCHEDULED ZOHO SYNC (Dec 19, 2025)
|
## 📋 PREVIOUS SESSION - SCHEDULED ZOHO SYNC (Dec 19, 2025)
|
||||||
|
|
||||||
### Status: ✅ **COMPLETE - WP-Cron Scheduled Sync Implemented**
|
### Status: ✅ **COMPLETE - WP-Cron Scheduled Sync Implemented**
|
||||||
|
|
|
||||||
|
|
@ -7,23 +7,23 @@
|
||||||
* @since 2.0.0
|
* @since 2.0.0
|
||||||
*/
|
*/
|
||||||
|
|
||||||
(function () {
|
(function() {
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
// Safety configuration
|
// Safety configuration
|
||||||
const config = window.HVAC_MapGeo_Config || {
|
const config = window.HVAC_MapGeo_Config || {
|
||||||
maxRetries: 3,
|
maxRetries: 3,
|
||||||
retryDelay: 2000,
|
retryDelay: 2000,
|
||||||
timeout: 30000, // Increased to 30s
|
timeout: 10000,
|
||||||
fallbackEnabled: true,
|
fallbackEnabled: true,
|
||||||
debugMode: false
|
debugMode: false
|
||||||
};
|
};
|
||||||
|
|
||||||
const log = config.debugMode ? console.log.bind(console) : () => { };
|
const log = config.debugMode ? console.log.bind(console) : () => {};
|
||||||
const error = config.debugMode ? console.error.bind(console) : () => { };
|
const error = config.debugMode ? console.error.bind(console) : () => {};
|
||||||
|
|
||||||
log('[MapGeo Safety] Initializing protection system');
|
log('[MapGeo Safety] Initializing protection system');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Resource Load Monitor
|
* Resource Load Monitor
|
||||||
* Tracks and manages external script loading
|
* Tracks and manages external script loading
|
||||||
|
|
@ -39,45 +39,45 @@
|
||||||
];
|
];
|
||||||
this.setupMonitoring();
|
this.setupMonitoring();
|
||||||
}
|
}
|
||||||
|
|
||||||
setupMonitoring() {
|
setupMonitoring() {
|
||||||
// Monitor script loading
|
// Monitor script loading
|
||||||
const originalAppendChild = Element.prototype.appendChild;
|
const originalAppendChild = Element.prototype.appendChild;
|
||||||
const self = this;
|
const self = this;
|
||||||
|
|
||||||
Element.prototype.appendChild = function (element) {
|
Element.prototype.appendChild = function(element) {
|
||||||
if (element.tagName === 'SCRIPT' && element.src) {
|
if (element.tagName === 'SCRIPT' && element.src) {
|
||||||
self.monitorScript(element);
|
self.monitorScript(element);
|
||||||
}
|
}
|
||||||
return originalAppendChild.call(this, element);
|
return originalAppendChild.call(this, element);
|
||||||
};
|
};
|
||||||
|
|
||||||
// Monitor existing scripts
|
// Monitor existing scripts
|
||||||
document.querySelectorAll('script[src]').forEach(script => {
|
document.querySelectorAll('script[src]').forEach(script => {
|
||||||
this.monitorScript(script);
|
this.monitorScript(script);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
monitorScript(script) {
|
monitorScript(script) {
|
||||||
const src = script.src;
|
const src = script.src;
|
||||||
const isCritical = this.criticalResources.some(resource =>
|
const isCritical = this.criticalResources.some(resource =>
|
||||||
src.toLowerCase().includes(resource)
|
src.toLowerCase().includes(resource)
|
||||||
);
|
);
|
||||||
|
|
||||||
if (isCritical) {
|
if (isCritical) {
|
||||||
log('[MapGeo Safety] Monitoring critical resource:', src);
|
log('[MapGeo Safety] Monitoring critical resource:', src);
|
||||||
|
|
||||||
const timeoutId = setTimeout(() => {
|
const timeoutId = setTimeout(() => {
|
||||||
error('[MapGeo Safety] Resource timeout:', src);
|
error('[MapGeo Safety] Resource timeout:', src);
|
||||||
this.handleResourceFailure(src);
|
this.handleResourceFailure(src);
|
||||||
}, config.timeout);
|
}, config.timeout);
|
||||||
|
|
||||||
script.addEventListener('load', () => {
|
script.addEventListener('load', () => {
|
||||||
clearTimeout(timeoutId);
|
clearTimeout(timeoutId);
|
||||||
log('[MapGeo Safety] Resource loaded:', src);
|
log('[MapGeo Safety] Resource loaded:', src);
|
||||||
this.resources.set(src, 'loaded');
|
this.resources.set(src, 'loaded');
|
||||||
});
|
});
|
||||||
|
|
||||||
script.addEventListener('error', () => {
|
script.addEventListener('error', () => {
|
||||||
clearTimeout(timeoutId);
|
clearTimeout(timeoutId);
|
||||||
error('[MapGeo Safety] Resource failed:', src);
|
error('[MapGeo Safety] Resource failed:', src);
|
||||||
|
|
@ -85,40 +85,40 @@
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
handleResourceFailure(src) {
|
handleResourceFailure(src) {
|
||||||
this.resources.set(src, 'failed');
|
this.resources.set(src, 'failed');
|
||||||
|
|
||||||
// Check if this is a MapGeo CDN resource
|
// Check if this is a MapGeo CDN resource
|
||||||
if (src.includes('cdn') || src.includes('amcharts')) {
|
if (src.includes('cdn') || src.includes('amcharts')) {
|
||||||
log('[MapGeo Safety] CDN resource failed, activating fallback');
|
log('[MapGeo Safety] CDN resource failed, activating fallback');
|
||||||
this.activateFallback();
|
this.activateFallback();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
activateFallback() {
|
activateFallback() {
|
||||||
// Hide map container
|
// Hide map container
|
||||||
const mapContainers = document.querySelectorAll(
|
const mapContainers = document.querySelectorAll(
|
||||||
'.igm-map-container, [class*="mapgeo"], [id*="map-"], .map-widget-container'
|
'.igm-map-container, [class*="mapgeo"], [id*="map-"], .map-widget-container'
|
||||||
);
|
);
|
||||||
|
|
||||||
mapContainers.forEach(container => {
|
mapContainers.forEach(container => {
|
||||||
container.style.display = 'none';
|
container.style.display = 'none';
|
||||||
});
|
});
|
||||||
|
|
||||||
// Show fallback content
|
// Show fallback content
|
||||||
const fallback = document.getElementById('hvac-map-fallback');
|
const fallback = document.getElementById('hvac-map-fallback');
|
||||||
if (fallback) {
|
if (fallback) {
|
||||||
fallback.style.display = 'block';
|
fallback.style.display = 'block';
|
||||||
}
|
}
|
||||||
|
|
||||||
// Dispatch custom event
|
// Dispatch custom event
|
||||||
window.dispatchEvent(new CustomEvent('hvac:mapgeo:fallback', {
|
window.dispatchEvent(new CustomEvent('hvac:mapgeo:fallback', {
|
||||||
detail: { reason: 'resource_failure' }
|
detail: { reason: 'resource_failure' }
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* MapGeo API Wrapper
|
* MapGeo API Wrapper
|
||||||
* Safely wraps MapGeo API calls
|
* Safely wraps MapGeo API calls
|
||||||
|
|
@ -127,7 +127,7 @@
|
||||||
constructor() {
|
constructor() {
|
||||||
this.wrapAPIs();
|
this.wrapAPIs();
|
||||||
}
|
}
|
||||||
|
|
||||||
wrapAPIs() {
|
wrapAPIs() {
|
||||||
// Wrap potential MapGeo global functions
|
// Wrap potential MapGeo global functions
|
||||||
const mapGeoAPIs = [
|
const mapGeoAPIs = [
|
||||||
|
|
@ -136,18 +136,18 @@
|
||||||
'IGM',
|
'IGM',
|
||||||
'mapWidget'
|
'mapWidget'
|
||||||
];
|
];
|
||||||
|
|
||||||
mapGeoAPIs.forEach(api => {
|
mapGeoAPIs.forEach(api => {
|
||||||
if (typeof window[api] !== 'undefined') {
|
if (typeof window[api] !== 'undefined') {
|
||||||
this.wrapAPI(api);
|
this.wrapAPI(api);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set up getter to wrap when loaded
|
// Set up getter to wrap when loaded
|
||||||
Object.defineProperty(window, `_original_${api}`, {
|
Object.defineProperty(window, `_original_${api}`, {
|
||||||
value: window[api],
|
value: window[api],
|
||||||
writable: true
|
writable: true
|
||||||
});
|
});
|
||||||
|
|
||||||
Object.defineProperty(window, api, {
|
Object.defineProperty(window, api, {
|
||||||
get() {
|
get() {
|
||||||
return window[`_wrapped_${api}`] || window[`_original_${api}`];
|
return window[`_wrapped_${api}`] || window[`_original_${api}`];
|
||||||
|
|
@ -176,10 +176,10 @@
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
wrapAPI(apiName) {
|
wrapAPI(apiName) {
|
||||||
const original = window[apiName];
|
const original = window[apiName];
|
||||||
|
|
||||||
window[apiName] = new Proxy(original, {
|
window[apiName] = new Proxy(original, {
|
||||||
construct(target, args) {
|
construct(target, args) {
|
||||||
try {
|
try {
|
||||||
|
|
@ -202,7 +202,7 @@
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* DOM Ready Safety
|
* DOM Ready Safety
|
||||||
* Ensures MapGeo only runs when DOM is safe
|
* Ensures MapGeo only runs when DOM is safe
|
||||||
|
|
@ -211,20 +211,20 @@
|
||||||
constructor() {
|
constructor() {
|
||||||
this.setupSafety();
|
this.setupSafety();
|
||||||
}
|
}
|
||||||
|
|
||||||
setupSafety() {
|
setupSafety() {
|
||||||
// Intercept jQuery ready calls that might contain MapGeo code
|
// Intercept jQuery ready calls that might contain MapGeo code
|
||||||
if (typeof jQuery !== 'undefined') {
|
if (typeof jQuery !== 'undefined') {
|
||||||
const originalReady = jQuery.fn.ready;
|
const originalReady = jQuery.fn.ready;
|
||||||
|
|
||||||
jQuery.fn.ready = function (callback) {
|
jQuery.fn.ready = function(callback) {
|
||||||
const wrappedCallback = function () {
|
const wrappedCallback = function() {
|
||||||
try {
|
try {
|
||||||
// Check if MapGeo elements exist before running
|
// Check if MapGeo elements exist before running
|
||||||
const hasMapElements = document.querySelector(
|
const hasMapElements = document.querySelector(
|
||||||
'.igm-map-container, [class*="mapgeo"], [id*="map-"]'
|
'.igm-map-container, [class*="mapgeo"], [id*="map-"]'
|
||||||
);
|
);
|
||||||
|
|
||||||
if (hasMapElements || !callback.toString().includes('map')) {
|
if (hasMapElements || !callback.toString().includes('map')) {
|
||||||
return callback.apply(this, arguments);
|
return callback.apply(this, arguments);
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -234,13 +234,13 @@
|
||||||
error('[MapGeo Safety] Error in ready callback:', e);
|
error('[MapGeo Safety] Error in ready callback:', e);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
return originalReady.call(this, wrappedCallback);
|
return originalReady.call(this, wrappedCallback);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* CDN Health Checker
|
* CDN Health Checker
|
||||||
* Proactively checks AmCharts CDN availability before MapGeo initialization
|
* Proactively checks AmCharts CDN availability before MapGeo initialization
|
||||||
|
|
@ -252,49 +252,49 @@
|
||||||
'https://cdn.amcharts.com/lib/version/4.10.29/maps.js',
|
'https://cdn.amcharts.com/lib/version/4.10.29/maps.js',
|
||||||
'https://cdn.amcharts.com/lib/4/geodata/usaLow.js'
|
'https://cdn.amcharts.com/lib/4/geodata/usaLow.js'
|
||||||
];
|
];
|
||||||
this.timeout = 15000; // Increased to 15s
|
this.timeout = 5000; // 5 second timeout
|
||||||
this.cacheKey = 'hvac_cdn_health';
|
this.cacheKey = 'hvac_cdn_health';
|
||||||
this.cacheExpiry = 10 * 60 * 1000; // 10 minutes
|
this.cacheExpiry = 10 * 60 * 1000; // 10 minutes
|
||||||
}
|
}
|
||||||
|
|
||||||
async checkCDNHealth() {
|
async checkCDNHealth() {
|
||||||
log('[MapGeo Safety] Checking AmCharts CDN health...');
|
log('[MapGeo Safety] Checking AmCharts CDN health...');
|
||||||
|
|
||||||
// Check cached result first
|
// Check cached result first
|
||||||
const cached = this.getCachedResult();
|
const cached = this.getCachedResult();
|
||||||
if (cached !== null) {
|
if (cached !== null) {
|
||||||
log('[MapGeo Safety] Using cached CDN status:', cached);
|
log('[MapGeo Safety] Using cached CDN status:', cached);
|
||||||
return cached;
|
return cached;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test primary CDN endpoints
|
// Test primary CDN endpoints
|
||||||
const results = await Promise.allSettled(
|
const results = await Promise.allSettled(
|
||||||
this.criticalCDNs.map(url => this.testCDNEndpoint(url))
|
this.criticalCDNs.map(url => this.testCDNEndpoint(url))
|
||||||
);
|
);
|
||||||
|
|
||||||
// Consider CDN healthy if at least 2 out of 3 endpoints work
|
// Consider CDN healthy if at least 2 out of 3 endpoints work
|
||||||
const successCount = results.filter(r => r.status === 'fulfilled' && r.value).length;
|
const successCount = results.filter(r => r.status === 'fulfilled' && r.value).length;
|
||||||
const isHealthy = successCount >= 2;
|
const isHealthy = successCount >= 2;
|
||||||
|
|
||||||
log(`[MapGeo Safety] CDN health check: ${successCount}/${this.criticalCDNs.length} endpoints available`);
|
log(`[MapGeo Safety] CDN health check: ${successCount}/${this.criticalCDNs.length} endpoints available`);
|
||||||
|
|
||||||
// Cache result
|
// Cache result
|
||||||
this.setCachedResult(isHealthy);
|
this.setCachedResult(isHealthy);
|
||||||
|
|
||||||
return isHealthy;
|
return isHealthy;
|
||||||
}
|
}
|
||||||
|
|
||||||
async testCDNEndpoint(url) {
|
async testCDNEndpoint(url) {
|
||||||
try {
|
try {
|
||||||
const controller = new AbortController();
|
const controller = new AbortController();
|
||||||
const timeoutId = setTimeout(() => controller.abort(), this.timeout);
|
const timeoutId = setTimeout(() => controller.abort(), this.timeout);
|
||||||
|
|
||||||
const response = await fetch(url, {
|
const response = await fetch(url, {
|
||||||
method: 'HEAD',
|
method: 'HEAD',
|
||||||
mode: 'no-cors', // Allow cross-origin requests
|
mode: 'no-cors', // Allow cross-origin requests
|
||||||
signal: controller.signal
|
signal: controller.signal
|
||||||
});
|
});
|
||||||
|
|
||||||
clearTimeout(timeoutId);
|
clearTimeout(timeoutId);
|
||||||
return true; // If we get here, endpoint is reachable
|
return true; // If we get here, endpoint is reachable
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
|
@ -302,7 +302,7 @@
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
getCachedResult() {
|
getCachedResult() {
|
||||||
try {
|
try {
|
||||||
const cached = sessionStorage.getItem(this.cacheKey);
|
const cached = sessionStorage.getItem(this.cacheKey);
|
||||||
|
|
@ -317,7 +317,7 @@
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
setCachedResult(healthy) {
|
setCachedResult(healthy) {
|
||||||
try {
|
try {
|
||||||
const data = {
|
const data = {
|
||||||
|
|
@ -330,7 +330,7 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize all safety systems with proactive CDN checking
|
* Initialize all safety systems with proactive CDN checking
|
||||||
*/
|
*/
|
||||||
|
|
@ -340,52 +340,52 @@
|
||||||
log('[MapGeo Safety] No map elements detected, skipping initialization');
|
log('[MapGeo Safety] No map elements detected, skipping initialization');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// CRITICAL: Check CDN health before allowing MapGeo to initialize
|
// CRITICAL: Check CDN health before allowing MapGeo to initialize
|
||||||
const cdnChecker = new CDNHealthChecker();
|
const cdnChecker = new CDNHealthChecker();
|
||||||
const cdnHealthy = await cdnChecker.checkCDNHealth();
|
const cdnHealthy = await cdnChecker.checkCDNHealth();
|
||||||
|
|
||||||
if (!cdnHealthy) {
|
if (!cdnHealthy) {
|
||||||
error('[MapGeo Safety] AmCharts CDN unavailable - activating immediate fallback');
|
error('[MapGeo Safety] AmCharts CDN unavailable - activating immediate fallback');
|
||||||
|
|
||||||
// Show fallback state
|
// Show fallback state
|
||||||
UIManager.showFallbackState();
|
UIManager.showFallbackState();
|
||||||
|
|
||||||
// Dispatch event to notify other systems
|
// Dispatch event to notify other systems
|
||||||
window.dispatchEvent(new CustomEvent('hvac:mapgeo:cdn_unavailable', {
|
window.dispatchEvent(new CustomEvent('hvac:mapgeo:cdn_unavailable', {
|
||||||
detail: { reason: 'amcharts_cdn_timeout' }
|
detail: { reason: 'amcharts_cdn_timeout' }
|
||||||
}));
|
}));
|
||||||
|
|
||||||
log('[MapGeo Safety] Immediate fallback activated due to CDN unavailability');
|
log('[MapGeo Safety] Immediate fallback activated due to CDN unavailability');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
log('[MapGeo Safety] AmCharts CDN healthy - proceeding with MapGeo initialization');
|
log('[MapGeo Safety] AmCharts CDN healthy - proceeding with MapGeo initialization');
|
||||||
|
|
||||||
// Show map state since CDN is healthy
|
// Show map state since CDN is healthy
|
||||||
UIManager.showMapState();
|
UIManager.showMapState();
|
||||||
|
|
||||||
// Initialize monitors
|
// Initialize monitors
|
||||||
new ResourceLoadMonitor();
|
new ResourceLoadMonitor();
|
||||||
new MapGeoAPIWrapper();
|
new MapGeoAPIWrapper();
|
||||||
new DOMReadySafety();
|
new DOMReadySafety();
|
||||||
|
|
||||||
// Set up periodic health check with shorter timeout now that we pre-checked CDN
|
// Set up periodic health check with shorter timeout now that we pre-checked CDN
|
||||||
let healthCheckCount = 0;
|
let healthCheckCount = 0;
|
||||||
const healthCheckInterval = setInterval(() => {
|
const healthCheckInterval = setInterval(() => {
|
||||||
healthCheckCount++;
|
healthCheckCount++;
|
||||||
|
|
||||||
// Check if map loaded successfully
|
// Check if map loaded successfully
|
||||||
const mapLoaded = document.querySelector('.igm-map-loaded, .mapgeo-loaded, .map-initialized');
|
const mapLoaded = document.querySelector('.igm-map-loaded, .mapgeo-loaded, .map-initialized');
|
||||||
|
|
||||||
if (mapLoaded) {
|
if (mapLoaded) {
|
||||||
log('[MapGeo Safety] Map loaded successfully');
|
log('[MapGeo Safety] Map loaded successfully');
|
||||||
clearInterval(healthCheckInterval);
|
clearInterval(healthCheckInterval);
|
||||||
} else if (healthCheckCount >= 30) {
|
} else if (healthCheckCount >= 6) {
|
||||||
// Increased to 30 seconds to match global timeout
|
// Reduced to 6 seconds since we already verified CDN
|
||||||
error('[MapGeo Safety] Map failed to load after 30 seconds');
|
error('[MapGeo Safety] Map failed to load after 6 seconds (CDN was healthy)');
|
||||||
clearInterval(healthCheckInterval);
|
clearInterval(healthCheckInterval);
|
||||||
|
|
||||||
// Activate fallback if configured
|
// Activate fallback if configured
|
||||||
if (config.fallbackEnabled) {
|
if (config.fallbackEnabled) {
|
||||||
const monitor = new ResourceLoadMonitor();
|
const monitor = new ResourceLoadMonitor();
|
||||||
|
|
@ -393,10 +393,10 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, 1000);
|
}, 1000);
|
||||||
|
|
||||||
log('[MapGeo Safety] All safety systems initialized with CDN pre-check');
|
log('[MapGeo Safety] All safety systems initialized with CDN pre-check');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Enhanced UI Management for CDN fallbacks
|
* Enhanced UI Management for CDN fallbacks
|
||||||
*/
|
*/
|
||||||
|
|
@ -405,55 +405,55 @@
|
||||||
const loading = document.getElementById('hvac-map-loading');
|
const loading = document.getElementById('hvac-map-loading');
|
||||||
const fallback = document.getElementById('hvac-map-fallback');
|
const fallback = document.getElementById('hvac-map-fallback');
|
||||||
const mapWrapper = document.querySelector('.hvac-mapgeo-wrapper');
|
const mapWrapper = document.querySelector('.hvac-mapgeo-wrapper');
|
||||||
|
|
||||||
if (loading) loading.style.display = 'block';
|
if (loading) loading.style.display = 'block';
|
||||||
if (fallback) fallback.style.display = 'none';
|
if (fallback) fallback.style.display = 'none';
|
||||||
if (mapWrapper) mapWrapper.style.display = 'none';
|
if (mapWrapper) mapWrapper.style.display = 'none';
|
||||||
|
|
||||||
log('[MapGeo Safety] Loading state activated');
|
log('[MapGeo Safety] Loading state activated');
|
||||||
}
|
}
|
||||||
|
|
||||||
static showFallbackState() {
|
static showFallbackState() {
|
||||||
const loading = document.getElementById('hvac-map-loading');
|
const loading = document.getElementById('hvac-map-loading');
|
||||||
const fallback = document.getElementById('hvac-map-fallback');
|
const fallback = document.getElementById('hvac-map-fallback');
|
||||||
const mapWrapper = document.querySelector('.hvac-mapgeo-wrapper');
|
const mapWrapper = document.querySelector('.hvac-mapgeo-wrapper');
|
||||||
|
|
||||||
if (loading) loading.style.display = 'none';
|
if (loading) loading.style.display = 'none';
|
||||||
if (fallback) fallback.style.display = 'block';
|
if (fallback) fallback.style.display = 'block';
|
||||||
if (mapWrapper) mapWrapper.style.display = 'none';
|
if (mapWrapper) mapWrapper.style.display = 'none';
|
||||||
|
|
||||||
log('[MapGeo Safety] Fallback state activated');
|
log('[MapGeo Safety] Fallback state activated');
|
||||||
}
|
}
|
||||||
|
|
||||||
static showMapState() {
|
static showMapState() {
|
||||||
const loading = document.getElementById('hvac-map-loading');
|
const loading = document.getElementById('hvac-map-loading');
|
||||||
const fallback = document.getElementById('hvac-map-fallback');
|
const fallback = document.getElementById('hvac-map-fallback');
|
||||||
const mapWrapper = document.querySelector('.hvac-mapgeo-wrapper');
|
const mapWrapper = document.querySelector('.hvac-mapgeo-wrapper');
|
||||||
|
|
||||||
if (loading) loading.style.display = 'none';
|
if (loading) loading.style.display = 'none';
|
||||||
if (fallback) fallback.style.display = 'none';
|
if (fallback) fallback.style.display = 'none';
|
||||||
if (mapWrapper) mapWrapper.style.display = 'block';
|
if (mapWrapper) mapWrapper.style.display = 'block';
|
||||||
|
|
||||||
log('[MapGeo Safety] Map state activated');
|
log('[MapGeo Safety] Map state activated');
|
||||||
}
|
}
|
||||||
|
|
||||||
static setupRetryButton() {
|
static setupRetryButton() {
|
||||||
const retryButton = document.querySelector('.hvac-retry-map');
|
const retryButton = document.querySelector('.hvac-retry-map');
|
||||||
if (retryButton) {
|
if (retryButton) {
|
||||||
retryButton.addEventListener('click', async () => {
|
retryButton.addEventListener('click', async () => {
|
||||||
retryButton.disabled = true;
|
retryButton.disabled = true;
|
||||||
retryButton.textContent = 'Checking...';
|
retryButton.textContent = 'Checking...';
|
||||||
|
|
||||||
try {
|
try {
|
||||||
UIManager.showLoadingState();
|
UIManager.showLoadingState();
|
||||||
|
|
||||||
// Clear CDN health cache
|
// Clear CDN health cache
|
||||||
const cdnChecker = new CDNHealthChecker();
|
const cdnChecker = new CDNHealthChecker();
|
||||||
sessionStorage.removeItem(cdnChecker.cacheKey);
|
sessionStorage.removeItem(cdnChecker.cacheKey);
|
||||||
|
|
||||||
// Re-check CDN health
|
// Re-check CDN health
|
||||||
const isHealthy = await cdnChecker.checkCDNHealth();
|
const isHealthy = await cdnChecker.checkCDNHealth();
|
||||||
|
|
||||||
if (isHealthy) {
|
if (isHealthy) {
|
||||||
log('[MapGeo Safety] CDN healthy on retry - reloading page');
|
log('[MapGeo Safety] CDN healthy on retry - reloading page');
|
||||||
window.location.reload();
|
window.location.reload();
|
||||||
|
|
@ -475,7 +475,7 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize when DOM is ready
|
// Initialize when DOM is ready
|
||||||
if (document.readyState === 'loading') {
|
if (document.readyState === 'loading') {
|
||||||
document.addEventListener('DOMContentLoaded', () => {
|
document.addEventListener('DOMContentLoaded', () => {
|
||||||
|
|
@ -489,7 +489,7 @@
|
||||||
UIManager.setupRetryButton();
|
UIManager.setupRetryButton();
|
||||||
initializeSafetySystems();
|
initializeSafetySystems();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Enhanced safety API for debugging and manual control
|
// Enhanced safety API for debugging and manual control
|
||||||
window.HVACMapGeoSafety = {
|
window.HVACMapGeoSafety = {
|
||||||
config: config,
|
config: config,
|
||||||
|
|
@ -509,5 +509,5 @@
|
||||||
log('[MapGeo Safety] CDN cache cleared');
|
log('[MapGeo Safety] CDN cache cleared');
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
})();
|
})();
|
||||||
|
|
@ -3,12 +3,12 @@
|
||||||
*
|
*
|
||||||
* @package HVACCommunityEvents
|
* @package HVACCommunityEvents
|
||||||
*/
|
*/
|
||||||
jQuery(document).ready(function ($) {
|
jQuery(document).ready(function($) {
|
||||||
|
|
||||||
// =====================================================
|
// =====================================================
|
||||||
// Password visibility toggle
|
// Password visibility toggle
|
||||||
// =====================================================
|
// =====================================================
|
||||||
$('#toggle-secret').on('click', function () {
|
$('#toggle-secret').on('click', function() {
|
||||||
var passwordField = $('#zoho_client_secret');
|
var passwordField = $('#zoho_client_secret');
|
||||||
var toggleBtn = $(this);
|
var toggleBtn = $(this);
|
||||||
|
|
||||||
|
|
@ -24,19 +24,19 @@ jQuery(document).ready(function ($) {
|
||||||
// =====================================================
|
// =====================================================
|
||||||
// Copy redirect URI to clipboard
|
// Copy redirect URI to clipboard
|
||||||
// =====================================================
|
// =====================================================
|
||||||
$('#copy-redirect-uri').on('click', function () {
|
$('#copy-redirect-uri').on('click', function() {
|
||||||
var redirectUri = hvacZoho.redirectUri || '';
|
var redirectUri = hvacZoho.redirectUri || '';
|
||||||
if (!redirectUri) {
|
if (!redirectUri) {
|
||||||
alert('Redirect URI not available');
|
alert('Redirect URI not available');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
navigator.clipboard.writeText(redirectUri).then(function () {
|
navigator.clipboard.writeText(redirectUri).then(function() {
|
||||||
$('#copy-redirect-uri').text('Copied!').prop('disabled', true);
|
$('#copy-redirect-uri').text('Copied!').prop('disabled', true);
|
||||||
setTimeout(function () {
|
setTimeout(function() {
|
||||||
$('#copy-redirect-uri').text('Copy').prop('disabled', false);
|
$('#copy-redirect-uri').text('Copy').prop('disabled', false);
|
||||||
}, 2000);
|
}, 2000);
|
||||||
}).catch(function () {
|
}).catch(function() {
|
||||||
// Fallback for older browsers
|
// Fallback for older browsers
|
||||||
var tempInput = $('<input>');
|
var tempInput = $('<input>');
|
||||||
$('body').append(tempInput);
|
$('body').append(tempInput);
|
||||||
|
|
@ -44,7 +44,7 @@ jQuery(document).ready(function ($) {
|
||||||
document.execCommand('copy');
|
document.execCommand('copy');
|
||||||
tempInput.remove();
|
tempInput.remove();
|
||||||
$('#copy-redirect-uri').text('Copied!').prop('disabled', true);
|
$('#copy-redirect-uri').text('Copied!').prop('disabled', true);
|
||||||
setTimeout(function () {
|
setTimeout(function() {
|
||||||
$('#copy-redirect-uri').text('Copy').prop('disabled', false);
|
$('#copy-redirect-uri').text('Copy').prop('disabled', false);
|
||||||
}, 2000);
|
}, 2000);
|
||||||
});
|
});
|
||||||
|
|
@ -53,21 +53,21 @@ jQuery(document).ready(function ($) {
|
||||||
// =====================================================
|
// =====================================================
|
||||||
// Flush rewrite rules
|
// Flush rewrite rules
|
||||||
// =====================================================
|
// =====================================================
|
||||||
$('#flush-rewrite-rules').on('click', function () {
|
$('#flush-rewrite-rules').on('click', function() {
|
||||||
var button = $(this);
|
var button = $(this);
|
||||||
button.prop('disabled', true).text('Flushing...');
|
button.prop('disabled', true).text('Flushing...');
|
||||||
|
|
||||||
$.post(hvacZoho.ajaxUrl, {
|
$.post(hvacZoho.ajaxUrl, {
|
||||||
action: 'hvac_zoho_flush_rewrite_rules'
|
action: 'hvac_zoho_flush_rewrite_rules'
|
||||||
}, function (response) {
|
}, function(response) {
|
||||||
if (response.success) {
|
if (response.success) {
|
||||||
button.text('Flushed!').css('color', '#46b450');
|
button.text('Flushed!').css('color', '#46b450');
|
||||||
setTimeout(function () {
|
setTimeout(function() {
|
||||||
location.reload();
|
location.reload();
|
||||||
}, 1000);
|
}, 1000);
|
||||||
} else {
|
} else {
|
||||||
button.text('Error').css('color', '#dc3232');
|
button.text('Error').css('color', '#dc3232');
|
||||||
setTimeout(function () {
|
setTimeout(function() {
|
||||||
button.prop('disabled', false).text('Flush Rules').css('color', '');
|
button.prop('disabled', false).text('Flush Rules').css('color', '');
|
||||||
}, 2000);
|
}, 2000);
|
||||||
}
|
}
|
||||||
|
|
@ -77,10 +77,7 @@ jQuery(document).ready(function ($) {
|
||||||
// =====================================================
|
// =====================================================
|
||||||
// Credentials form submission
|
// Credentials form submission
|
||||||
// =====================================================
|
// =====================================================
|
||||||
// =====================================================
|
$('#zoho-credentials-form').on('submit', function(e) {
|
||||||
// Credentials form submission
|
|
||||||
// =====================================================
|
|
||||||
$('#zoho-credentials-form').on('submit', function (e) {
|
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|
||||||
var formData = {
|
var formData = {
|
||||||
|
|
@ -90,73 +87,14 @@ jQuery(document).ready(function ($) {
|
||||||
nonce: $('input[name="hvac_zoho_nonce"]').val()
|
nonce: $('input[name="hvac_zoho_nonce"]').val()
|
||||||
};
|
};
|
||||||
|
|
||||||
var $saveBtn = $('#save-credentials');
|
$('#save-credentials').prop('disabled', true).text('Saving...');
|
||||||
$saveBtn.prop('disabled', true).text('Saving...');
|
|
||||||
|
|
||||||
// Clear any previous messages
|
$.post(hvacZoho.ajaxUrl, formData, function(response) {
|
||||||
$('.notice').remove();
|
if (response.success) {
|
||||||
|
window.location.href = window.location.href.split('?')[0] + '?page=hvac-zoho-sync&credentials_saved=1';
|
||||||
$.ajax({
|
} else {
|
||||||
url: hvacZoho.ajaxUrl,
|
alert('Error saving credentials: ' + response.data.message);
|
||||||
method: 'POST',
|
$('#save-credentials').prop('disabled', false).text('Save Credentials');
|
||||||
data: formData,
|
|
||||||
success: function (response) {
|
|
||||||
if (response.success) {
|
|
||||||
window.location.href = window.location.href.split('?')[0] + '?page=hvac-zoho-sync&credentials_saved=1';
|
|
||||||
} else {
|
|
||||||
// Create error notice
|
|
||||||
var errorHtml = '<div class="notice notice-error is-dismissible"><p>' +
|
|
||||||
'<strong>Error saving credentials:</strong> ' + response.data.message +
|
|
||||||
'</p></div>';
|
|
||||||
$('h1').after(errorHtml);
|
|
||||||
|
|
||||||
$saveBtn.prop('disabled', false).text('Save Credentials');
|
|
||||||
}
|
|
||||||
},
|
|
||||||
error: function (xhr, status, error) {
|
|
||||||
console.error('Zoho Save Error:', xhr);
|
|
||||||
|
|
||||||
var errorMessage = 'Unknown error occurred';
|
|
||||||
var errorDetails = '';
|
|
||||||
|
|
||||||
if (xhr.status === 400 || xhr.status === 403) {
|
|
||||||
errorMessage = 'Request blocked (' + xhr.status + ')';
|
|
||||||
errorDetails = 'This is likely due to a security plugin or Web Application Firewall (WAF) blocking the request. ' +
|
|
||||||
'The content (e.g. Client Secret) might be triggering a false positive security rule.';
|
|
||||||
} else if (xhr.status === 500) {
|
|
||||||
errorMessage = 'Server Error (500)';
|
|
||||||
errorDetails = 'Check the server error logs for more information.';
|
|
||||||
} else if (status === 'timeout') {
|
|
||||||
errorMessage = 'Request timed out';
|
|
||||||
} else if (xhr.responseJSON && xhr.responseJSON.data && xhr.responseJSON.data.message) {
|
|
||||||
errorMessage = xhr.responseJSON.data.message;
|
|
||||||
} else {
|
|
||||||
errorMessage = error || status;
|
|
||||||
}
|
|
||||||
|
|
||||||
var errorHtml = '<div class="notice notice-error is-dismissible" style="border-left-color: #dc3232;">' +
|
|
||||||
'<p><strong>❌ Save Failed:</strong> ' + errorMessage + '</p>';
|
|
||||||
|
|
||||||
if (errorDetails) {
|
|
||||||
errorHtml += '<p><em>' + errorDetails + '</em></p>';
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add debug details
|
|
||||||
errorHtml += '<details style="margin-top: 10px;">' +
|
|
||||||
'<summary>Technical Details</summary>' +
|
|
||||||
'<ul style="margin-top: 5px; font-size: 12px; background: #f0f0f0; padding: 10px;">' +
|
|
||||||
'<li>Status: ' + xhr.status + ' ' + xhr.statusText + '</li>' +
|
|
||||||
'<li>Response: ' + (xhr.responseText ? xhr.responseText.substring(0, 100) + '...' : '(empty)') + '</li>' +
|
|
||||||
'</ul>' +
|
|
||||||
'</details></div>';
|
|
||||||
|
|
||||||
$('h1').after(errorHtml);
|
|
||||||
|
|
||||||
// Re-enable button
|
|
||||||
$saveBtn.prop('disabled', false).text('Save Credentials');
|
|
||||||
|
|
||||||
// Scroll to error
|
|
||||||
$('html, body').animate({ scrollTop: 0 }, 'slow');
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
@ -164,7 +102,7 @@ jQuery(document).ready(function ($) {
|
||||||
// =====================================================
|
// =====================================================
|
||||||
// OAuth authorization handler
|
// OAuth authorization handler
|
||||||
// =====================================================
|
// =====================================================
|
||||||
$('#start-oauth').on('click', function () {
|
$('#start-oauth').on('click', function() {
|
||||||
var clientId = $('#zoho_client_id').val();
|
var clientId = $('#zoho_client_id').val();
|
||||||
var clientSecret = $('#zoho_client_secret').val();
|
var clientSecret = $('#zoho_client_secret').val();
|
||||||
|
|
||||||
|
|
@ -188,13 +126,13 @@ jQuery(document).ready(function ($) {
|
||||||
// =====================================================
|
// =====================================================
|
||||||
// Test connection
|
// Test connection
|
||||||
// =====================================================
|
// =====================================================
|
||||||
$('#test-connection').on('click', function () {
|
$('#test-connection').on('click', function() {
|
||||||
var $button = $(this);
|
var $button = $(this);
|
||||||
var $status = $('#connection-status');
|
var $status = $('#connection-status');
|
||||||
|
|
||||||
$button.prop('disabled', true).text('Testing...');
|
$button.prop('disabled', true).text('Testing...');
|
||||||
$status.html('');
|
$status.html('');
|
||||||
|
|
||||||
$.ajax({
|
$.ajax({
|
||||||
url: hvacZoho.ajaxUrl,
|
url: hvacZoho.ajaxUrl,
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
|
|
@ -202,11 +140,11 @@ jQuery(document).ready(function ($) {
|
||||||
action: 'hvac_zoho_test_connection',
|
action: 'hvac_zoho_test_connection',
|
||||||
nonce: hvacZoho.nonce
|
nonce: hvacZoho.nonce
|
||||||
},
|
},
|
||||||
success: function (response) {
|
success: function(response) {
|
||||||
if (response.success) {
|
if (response.success) {
|
||||||
var successHtml = '<div class="notice notice-success">';
|
var successHtml = '<div class="notice notice-success">';
|
||||||
successHtml += '<p><strong>' + response.data.message + '</strong></p>';
|
successHtml += '<p><strong>' + response.data.message + '</strong></p>';
|
||||||
|
|
||||||
// Show credential details
|
// Show credential details
|
||||||
if (response.data.client_id) {
|
if (response.data.client_id) {
|
||||||
successHtml += '<p>Client ID: ' + response.data.client_id + '</p>';
|
successHtml += '<p>Client ID: ' + response.data.client_id + '</p>';
|
||||||
|
|
@ -219,7 +157,7 @@ jQuery(document).ready(function ($) {
|
||||||
} else {
|
} else {
|
||||||
successHtml += '<p>Refresh Token: ❌ Missing (OAuth required)</p>';
|
successHtml += '<p>Refresh Token: ❌ Missing (OAuth required)</p>';
|
||||||
}
|
}
|
||||||
|
|
||||||
// Show debug info if available
|
// Show debug info if available
|
||||||
if (response.data.debug) {
|
if (response.data.debug) {
|
||||||
successHtml += '<details style="margin-top: 10px;">';
|
successHtml += '<details style="margin-top: 10px;">';
|
||||||
|
|
@ -228,7 +166,7 @@ jQuery(document).ready(function ($) {
|
||||||
successHtml += JSON.stringify(response.data.debug, null, 2);
|
successHtml += JSON.stringify(response.data.debug, null, 2);
|
||||||
successHtml += '</pre></details>';
|
successHtml += '</pre></details>';
|
||||||
}
|
}
|
||||||
|
|
||||||
successHtml += '</div>';
|
successHtml += '</div>';
|
||||||
$status.html(successHtml);
|
$status.html(successHtml);
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -236,23 +174,23 @@ jQuery(document).ready(function ($) {
|
||||||
console.log('Error response:', response);
|
console.log('Error response:', response);
|
||||||
console.log('Message:', response.data.message);
|
console.log('Message:', response.data.message);
|
||||||
console.log('Has auth_url:', !!response.data.auth_url);
|
console.log('Has auth_url:', !!response.data.auth_url);
|
||||||
|
|
||||||
// Handle OAuth authorization case specially
|
// Handle OAuth authorization case specially
|
||||||
if (response.data.message === 'OAuth Authorization Required' && response.data.auth_url) {
|
if (response.data.message === 'OAuth Authorization Required' && response.data.auth_url) {
|
||||||
var authHtml = '<div class="notice notice-warning">';
|
var authHtml = '<div class="notice notice-warning">';
|
||||||
authHtml += '<h3>🔐 OAuth Authorization Required</h3>';
|
authHtml += '<h3>🔐 OAuth Authorization Required</h3>';
|
||||||
authHtml += '<p><strong>' + response.data.details + '</strong></p>';
|
authHtml += '<p><strong>' + response.data.details + '</strong></p>';
|
||||||
|
|
||||||
if (response.data.next_steps) {
|
if (response.data.next_steps) {
|
||||||
authHtml += '<ol>';
|
authHtml += '<ol>';
|
||||||
response.data.next_steps.forEach(function (step) {
|
response.data.next_steps.forEach(function(step) {
|
||||||
authHtml += '<li>' + step + '</li>';
|
authHtml += '<li>' + step + '</li>';
|
||||||
});
|
});
|
||||||
authHtml += '</ol>';
|
authHtml += '</ol>';
|
||||||
}
|
}
|
||||||
|
|
||||||
authHtml += '<p><a href="' + response.data.auth_url + '" target="_blank" class="button button-primary" style="margin: 10px 0;">🚀 Authorize with Zoho CRM</a></p>';
|
authHtml += '<p><a href="' + response.data.auth_url + '" target="_blank" class="button button-primary" style="margin: 10px 0;">🚀 Authorize with Zoho CRM</a></p>';
|
||||||
|
|
||||||
// Show credential status
|
// Show credential status
|
||||||
if (response.data.credentials_status) {
|
if (response.data.credentials_status) {
|
||||||
authHtml += '<p><strong>Current Status:</strong></p>';
|
authHtml += '<p><strong>Current Status:</strong></p>';
|
||||||
|
|
@ -262,7 +200,7 @@ jQuery(document).ready(function ($) {
|
||||||
authHtml += '<li>Refresh Token: ' + (response.data.credentials_status.refresh_token_exists ? '✓ Found' : '❌ Missing') + '</li>';
|
authHtml += '<li>Refresh Token: ' + (response.data.credentials_status.refresh_token_exists ? '✓ Found' : '❌ Missing') + '</li>';
|
||||||
authHtml += '</ul>';
|
authHtml += '</ul>';
|
||||||
}
|
}
|
||||||
|
|
||||||
authHtml += '<p><em>After authorization, come back and test the connection again.</em></p>';
|
authHtml += '<p><em>After authorization, come back and test the connection again.</em></p>';
|
||||||
authHtml += '</div>';
|
authHtml += '</div>';
|
||||||
$status.html(authHtml);
|
$status.html(authHtml);
|
||||||
|
|
@ -272,260 +210,141 @@ jQuery(document).ready(function ($) {
|
||||||
console.log('Message matches:', response.data.message === 'OAuth Authorization Required');
|
console.log('Message matches:', response.data.message === 'OAuth Authorization Required');
|
||||||
console.log('Auth URL exists:', !!response.data.auth_url);
|
console.log('Auth URL exists:', !!response.data.auth_url);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create detailed error display for other errors
|
// Create detailed error display for other errors
|
||||||
var errorHtml = '<div class="notice notice-error">';
|
var errorHtml = '<div class="notice notice-error">';
|
||||||
errorHtml += '<p><strong>' + response.data.message + ':</strong> ' + response.data.error + '</p>';
|
errorHtml += '<p><strong>' + response.data.message + ':</strong> ' + response.data.error + '</p>';
|
||||||
|
|
||||||
// Add error code if available
|
// Add error code if available
|
||||||
if (response.data.code) {
|
if (response.data.code) {
|
||||||
errorHtml += '<p><strong>Error Code:</strong> ' + response.data.code + '</p>';
|
errorHtml += '<p><strong>Error Code:</strong> ' + response.data.code + '</p>';
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add details if available
|
// Add details if available
|
||||||
if (response.data.details) {
|
if (response.data.details) {
|
||||||
errorHtml += '<p><strong>Details:</strong> ' + response.data.details + '</p>';
|
errorHtml += '<p><strong>Details:</strong> ' + response.data.details + '</p>';
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add debugging info
|
// Add debugging info
|
||||||
errorHtml += '<div class="hvac-zoho-debug-info">';
|
errorHtml += '<div class="hvac-zoho-debug-info">';
|
||||||
errorHtml += '<p><strong>Debug Information:</strong></p>';
|
errorHtml += '<p><strong>Debug Information:</strong></p>';
|
||||||
errorHtml += '<p>Check the PHP error log for more details.</p>';
|
errorHtml += '<p>Check the PHP error log for more details.</p>';
|
||||||
errorHtml += '<p>Log location: wp-content/plugins/hvac-community-events/logs/zoho-debug.log</p>';
|
errorHtml += '<p>Log location: wp-content/plugins/hvac-community-events/logs/zoho-debug.log</p>';
|
||||||
|
|
||||||
// Add raw response data if available
|
// Add raw response data if available
|
||||||
if (response.data.raw) {
|
if (response.data.raw) {
|
||||||
errorHtml += '<details>';
|
errorHtml += '<details>';
|
||||||
errorHtml += '<summary>Raw Response Data (click to expand)</summary>';
|
errorHtml += '<summary>Raw Response Data (click to expand)</summary>';
|
||||||
errorHtml += '<pre style="background: #f0f0f0; padding: 10px; max-height: 300px; overflow: auto;">' +
|
errorHtml += '<pre style="background: #f0f0f0; padding: 10px; max-height: 300px; overflow: auto;">' +
|
||||||
JSON.stringify(JSON.parse(response.data.raw), null, 2) +
|
JSON.stringify(JSON.parse(response.data.raw), null, 2) +
|
||||||
'</pre>';
|
'</pre>';
|
||||||
errorHtml += '</details>';
|
errorHtml += '</details>';
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add file/line info if available (for exceptions)
|
// Add file/line info if available (for exceptions)
|
||||||
if (response.data.file) {
|
if (response.data.file) {
|
||||||
errorHtml += '<p><strong>File:</strong> ' + response.data.file + '</p>';
|
errorHtml += '<p><strong>File:</strong> ' + response.data.file + '</p>';
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add trace if available
|
// Add trace if available
|
||||||
if (response.data.trace) {
|
if (response.data.trace) {
|
||||||
errorHtml += '<details>';
|
errorHtml += '<details>';
|
||||||
errorHtml += '<summary>Stack Trace (click to expand)</summary>';
|
errorHtml += '<summary>Stack Trace (click to expand)</summary>';
|
||||||
errorHtml += '<pre style="background: #f0f0f0; padding: 10px; max-height: 300px; overflow: auto;">' +
|
errorHtml += '<pre style="background: #f0f0f0; padding: 10px; max-height: 300px; overflow: auto;">' +
|
||||||
response.data.trace +
|
response.data.trace +
|
||||||
'</pre>';
|
'</pre>';
|
||||||
errorHtml += '</details>';
|
errorHtml += '</details>';
|
||||||
}
|
}
|
||||||
|
|
||||||
errorHtml += '</div>'; // Close debug info
|
errorHtml += '</div>'; // Close debug info
|
||||||
errorHtml += '</div>'; // Close notice
|
errorHtml += '</div>'; // Close notice
|
||||||
|
|
||||||
$status.html(errorHtml);
|
$status.html(errorHtml);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
error: function (xhr, status, error) {
|
error: function(xhr, status, error) {
|
||||||
var errorHtml = '<div class="notice notice-error">';
|
var errorHtml = '<div class="notice notice-error">';
|
||||||
errorHtml += '<p><strong>AJAX Error:</strong> Connection test failed</p>';
|
errorHtml += '<p><strong>AJAX Error:</strong> Connection test failed</p>';
|
||||||
errorHtml += '<p><strong>Status:</strong> ' + status + '</p>';
|
errorHtml += '<p><strong>Status:</strong> ' + status + '</p>';
|
||||||
errorHtml += '<p><strong>Error:</strong> ' + error + '</p>';
|
errorHtml += '<p><strong>Error:</strong> ' + error + '</p>';
|
||||||
errorHtml += '</div>';
|
errorHtml += '</div>';
|
||||||
|
|
||||||
$status.html(errorHtml);
|
$status.html(errorHtml);
|
||||||
},
|
},
|
||||||
complete: function () {
|
complete: function() {
|
||||||
$button.prop('disabled', false).text('Test Connection');
|
$button.prop('disabled', false).text('Test Connection');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// =====================================================
|
// Sync data
|
||||||
// Sync data with batch progress
|
$('.sync-button').on('click', function() {
|
||||||
// =====================================================
|
var $button = $(this);
|
||||||
|
var type = $button.data('type');
|
||||||
/**
|
var $status = $('#' + type + '-status');
|
||||||
* Sync with progress - auto-continues through all batches
|
|
||||||
* @param {jQuery} $button - The sync button
|
$button.prop('disabled', true).text('Syncing...');
|
||||||
* @param {string} type - Sync type (events, users, attendees, rsvps, purchases)
|
$status.html('<p>Syncing ' + type + '...</p>');
|
||||||
* @param {jQuery} $status - Status container element
|
|
||||||
* @param {number} offset - Current offset
|
|
||||||
* @param {object} accumulated - Accumulated results across batches
|
|
||||||
*/
|
|
||||||
function syncWithProgress($button, type, $status, offset, accumulated) {
|
|
||||||
accumulated = accumulated || {
|
|
||||||
synced: 0,
|
|
||||||
failed: 0,
|
|
||||||
errors: [],
|
|
||||||
total: 0,
|
|
||||||
staging_mode: false,
|
|
||||||
responses: [],
|
|
||||||
test_data: []
|
|
||||||
};
|
|
||||||
|
|
||||||
$.ajax({
|
$.ajax({
|
||||||
url: hvacZoho.ajaxUrl,
|
url: hvacZoho.ajaxUrl,
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
data: {
|
data: {
|
||||||
action: 'hvac_zoho_sync_data',
|
action: 'hvac_zoho_sync_data',
|
||||||
type: type,
|
type: type,
|
||||||
offset: offset,
|
|
||||||
nonce: hvacZoho.nonce
|
nonce: hvacZoho.nonce
|
||||||
},
|
},
|
||||||
success: function (response) {
|
success: function(response) {
|
||||||
if (response.success) {
|
if (response.success) {
|
||||||
var result = response.data;
|
var result = response.data;
|
||||||
|
var html = '<div class="notice notice-success">';
|
||||||
// Update accumulated totals
|
|
||||||
accumulated.total = result.total; // Total is consistent across batches
|
if (result.staging_mode) {
|
||||||
accumulated.synced += result.synced;
|
html += '<h4>🔧 STAGING MODE - Simulation Results</h4>';
|
||||||
accumulated.failed += result.failed;
|
html += '<p>' + result.message + '</p>';
|
||||||
accumulated.staging_mode = result.staging_mode;
|
|
||||||
|
|
||||||
// Merge arrays
|
|
||||||
if (result.errors && result.errors.length > 0) {
|
|
||||||
accumulated.errors = accumulated.errors.concat(result.errors);
|
|
||||||
}
|
|
||||||
if (result.responses && result.responses.length > 0) {
|
|
||||||
accumulated.responses = accumulated.responses.concat(result.responses);
|
|
||||||
}
|
|
||||||
if (result.test_data && result.test_data.length > 0) {
|
|
||||||
accumulated.test_data = accumulated.test_data.concat(result.test_data);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Calculate progress
|
|
||||||
var processed = accumulated.synced + accumulated.failed;
|
|
||||||
var percent = accumulated.total > 0 ? Math.round((processed / accumulated.total) * 100) : 0;
|
|
||||||
|
|
||||||
// Update progress bar
|
|
||||||
var progressHtml = '<div class="sync-progress-bar" style="margin: 10px 0;">' +
|
|
||||||
'<div style="background: #e0e0e0; border-radius: 4px; overflow: hidden; height: 20px;">' +
|
|
||||||
'<div style="background: linear-gradient(90deg, #0073aa, #00a0d2); height: 100%; width: ' + percent + '%; transition: width 0.3s;"></div>' +
|
|
||||||
'</div>' +
|
|
||||||
'<p style="margin: 5px 0; font-size: 13px;">' +
|
|
||||||
'<strong>' + processed + ' of ' + accumulated.total + '</strong> processed (' + percent + '%)' +
|
|
||||||
'</p></div>';
|
|
||||||
$status.html(progressHtml);
|
|
||||||
|
|
||||||
// Check if there are more batches
|
|
||||||
if (result.has_more && result.next_offset > offset) {
|
|
||||||
// Continue with next batch
|
|
||||||
syncWithProgress($button, type, $status, result.next_offset, accumulated);
|
|
||||||
} else {
|
} else {
|
||||||
// All done! Show final results
|
html += '<p>Sync completed successfully!</p>';
|
||||||
displaySyncResults($button, type, $status, accumulated, result);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
html += '<ul>' +
|
||||||
|
'<li>Total records: ' + result.total + '</li>' +
|
||||||
|
'<li>Synced: ' + result.synced + '</li>' +
|
||||||
|
'<li>Failed: ' + result.failed + '</li>' +
|
||||||
|
'</ul>';
|
||||||
|
|
||||||
|
if (result.test_data && result.test_data.length > 0) {
|
||||||
|
html += '<details>' +
|
||||||
|
'<summary>View test data (first 5 records)</summary>' +
|
||||||
|
'<pre style="background: #f0f0f0; padding: 10px; overflow: auto;">' +
|
||||||
|
JSON.stringify(result.test_data.slice(0, 5), null, 2) +
|
||||||
|
'</pre>' +
|
||||||
|
'</details>';
|
||||||
|
}
|
||||||
|
|
||||||
|
html += '</div>';
|
||||||
|
$status.html(html);
|
||||||
} else {
|
} else {
|
||||||
$status.html('<div class="notice notice-error"><p>' + response.data.message + ': ' + response.data.error + '</p></div>');
|
$status.html('<div class="notice notice-error"><p>' + response.data.message + ': ' + response.data.error + '</p></div>');
|
||||||
$button.prop('disabled', false).text('Sync ' + type.charAt(0).toUpperCase() + type.slice(1));
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
error: function () {
|
error: function() {
|
||||||
$status.html('<div class="notice notice-error"><p>Sync failed - network or server error</p></div>');
|
$status.html('<div class="notice notice-error"><p>Sync failed</p></div>');
|
||||||
|
},
|
||||||
|
complete: function() {
|
||||||
$button.prop('disabled', false).text('Sync ' + type.charAt(0).toUpperCase() + type.slice(1));
|
$button.prop('disabled', false).text('Sync ' + type.charAt(0).toUpperCase() + type.slice(1));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Display final sync results
|
|
||||||
*/
|
|
||||||
function displaySyncResults($button, type, $status, accumulated, lastResult) {
|
|
||||||
var html = '<div class="notice notice-success">';
|
|
||||||
|
|
||||||
if (accumulated.staging_mode) {
|
|
||||||
html += '<h4>🔧 STAGING MODE - Simulation Complete</h4>';
|
|
||||||
html += '<p>No data was sent to Zoho CRM. This is a dry-run showing what would sync.</p>';
|
|
||||||
} else {
|
|
||||||
html += '<p><strong>✅ Sync completed successfully!</strong></p>';
|
|
||||||
}
|
|
||||||
|
|
||||||
if (lastResult.version) {
|
|
||||||
html += '<p><strong>Server Code Version:</strong> ' + lastResult.version + '</p>';
|
|
||||||
}
|
|
||||||
|
|
||||||
html += '<ul>' +
|
|
||||||
'<li>Total records: ' + accumulated.total + '</li>' +
|
|
||||||
'<li>Synced: ' + accumulated.synced + '</li>' +
|
|
||||||
'<li>Failed: ' + accumulated.failed + '</li>' +
|
|
||||||
'</ul>';
|
|
||||||
|
|
||||||
// Show test data for staging
|
|
||||||
if (accumulated.test_data && accumulated.test_data.length > 0) {
|
|
||||||
html += '<details>' +
|
|
||||||
'<summary>View test data (first 5 records)</summary>' +
|
|
||||||
'<pre style="background: #f0f0f0; padding: 10px; overflow: auto; max-height: 300px;">' +
|
|
||||||
JSON.stringify(accumulated.test_data.slice(0, 5), null, 2) +
|
|
||||||
'</pre>' +
|
|
||||||
'</details>';
|
|
||||||
}
|
|
||||||
|
|
||||||
// Debug info
|
|
||||||
if (lastResult.debug_info) {
|
|
||||||
html += '<details style="margin-top: 10px;">' +
|
|
||||||
'<summary>🔍 Debug: Mode Detection Info</summary>' +
|
|
||||||
'<div style="background: #f0f0f0; padding: 10px; font-size: 12px; margin-top: 5px;">';
|
|
||||||
|
|
||||||
if (typeof lastResult.debug_info.is_staging !== 'undefined') {
|
|
||||||
html += '<p><strong>Is Staging:</strong> ' + (lastResult.debug_info.is_staging ? '✅ YES' : '❌ NO') + '</p>';
|
|
||||||
}
|
|
||||||
if (lastResult.debug_info.site_url) {
|
|
||||||
html += '<p><strong>Site URL:</strong> ' + lastResult.debug_info.site_url + '</p>';
|
|
||||||
}
|
|
||||||
|
|
||||||
html += '<pre style="background: #e0e0e0; padding: 5px; margin-top: 5px; max-height: 150px; overflow: auto;">' +
|
|
||||||
JSON.stringify(lastResult.debug_info, null, 2) +
|
|
||||||
'</pre>' +
|
|
||||||
'</div>' +
|
|
||||||
'</details>';
|
|
||||||
}
|
|
||||||
|
|
||||||
// Show errors if any
|
|
||||||
if (accumulated.errors && accumulated.errors.length > 0) {
|
|
||||||
html += '<details style="margin-top: 10px; border: 2px solid #dc3232;">' +
|
|
||||||
'<summary style="font-weight: bold; color: #dc3232;">❌ Errors (' + accumulated.errors.length + ')</summary>' +
|
|
||||||
'<pre style="background: #fff0f0; padding: 10px; overflow: auto; max-height: 300px;">' +
|
|
||||||
JSON.stringify(accumulated.errors.slice(0, 20), null, 2) +
|
|
||||||
'</pre>' +
|
|
||||||
'</details>';
|
|
||||||
}
|
|
||||||
|
|
||||||
// Show API responses preview
|
|
||||||
if (accumulated.responses && accumulated.responses.length > 0) {
|
|
||||||
html += '<details style="margin-top: 10px;">' +
|
|
||||||
'<summary>📡 Raw API Responses (first 10)</summary>' +
|
|
||||||
'<pre style="background: #f0f0f0; padding: 10px; overflow: auto; max-height: 200px;">' +
|
|
||||||
JSON.stringify(accumulated.responses.slice(0, 10), null, 2) +
|
|
||||||
'</pre>' +
|
|
||||||
'</details>';
|
|
||||||
}
|
|
||||||
|
|
||||||
html += '</div>';
|
|
||||||
$status.html(html);
|
|
||||||
$button.prop('disabled', false).text('Sync ' + type.charAt(0).toUpperCase() + type.slice(1));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sync button click handler
|
|
||||||
$('.sync-button').on('click', function () {
|
|
||||||
var $button = $(this);
|
|
||||||
var type = $button.data('type');
|
|
||||||
var $status = $('#' + type + '-status');
|
|
||||||
|
|
||||||
$button.prop('disabled', true).text('Syncing...');
|
|
||||||
$status.html('<p>Starting sync for ' + type + '...</p>');
|
|
||||||
|
|
||||||
// Start sync with batch progress
|
|
||||||
syncWithProgress($button, type, $status, 0, null);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Save settings
|
// Save settings
|
||||||
$('#zoho-settings-form').on('submit', function (e) {
|
$('#zoho-settings-form').on('submit', function(e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|
||||||
var $form = $(this);
|
var $form = $(this);
|
||||||
var $button = $form.find('button[type="submit"]');
|
var $button = $form.find('button[type="submit"]');
|
||||||
|
|
||||||
$button.prop('disabled', true).text('Saving...');
|
$button.prop('disabled', true).text('Saving...');
|
||||||
|
|
||||||
$.ajax({
|
$.ajax({
|
||||||
url: hvacZoho.ajaxUrl,
|
url: hvacZoho.ajaxUrl,
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
|
|
@ -535,10 +354,14 @@ jQuery(document).ready(function ($) {
|
||||||
auto_sync: $form.find('input[name="auto_sync"]').is(':checked') ? '1' : '0',
|
auto_sync: $form.find('input[name="auto_sync"]').is(':checked') ? '1' : '0',
|
||||||
sync_frequency: $form.find('select[name="sync_frequency"]').val()
|
sync_frequency: $form.find('select[name="sync_frequency"]').val()
|
||||||
},
|
},
|
||||||
success: function (response) {
|
success: function(response) {
|
||||||
if (response.success) {
|
if (response.success) {
|
||||||
// Reload page to show updated status
|
// Use toast notification instead of alert
|
||||||
window.location.reload();
|
if (window.HVACToast) {
|
||||||
|
HVACToast.success('Settings saved successfully!');
|
||||||
|
} else {
|
||||||
|
alert('Settings saved successfully!');
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// Use toast notification instead of alert
|
// Use toast notification instead of alert
|
||||||
if (window.HVACToast) {
|
if (window.HVACToast) {
|
||||||
|
|
@ -546,161 +369,19 @@ jQuery(document).ready(function ($) {
|
||||||
} else {
|
} else {
|
||||||
alert('Error saving settings: ' + response.data.message);
|
alert('Error saving settings: ' + response.data.message);
|
||||||
}
|
}
|
||||||
$button.prop('disabled', false).text('Save Settings');
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
error: function () {
|
error: function() {
|
||||||
// Use toast notification instead of alert
|
// Use toast notification instead of alert
|
||||||
if (window.HVACToast) {
|
if (window.HVACToast) {
|
||||||
HVACToast.error('Error saving settings');
|
HVACToast.error('Error saving settings');
|
||||||
} else {
|
} else {
|
||||||
alert('Error saving settings');
|
alert('Error saving settings');
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
complete: function() {
|
||||||
$button.prop('disabled', false).text('Save Settings');
|
$button.prop('disabled', false).text('Save Settings');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// =====================================================
|
|
||||||
// Run Scheduled Sync Now Handler
|
|
||||||
// =====================================================
|
|
||||||
$('#run-scheduled-sync-now').on('click', function () {
|
|
||||||
var $button = $(this);
|
|
||||||
var $status = $('#scheduled-sync-status');
|
|
||||||
|
|
||||||
$button.prop('disabled', true).text('Running...');
|
|
||||||
$status.html('<p>Starting scheduled sync...</p>');
|
|
||||||
|
|
||||||
$.ajax({
|
|
||||||
url: hvacZoho.ajaxUrl,
|
|
||||||
method: 'POST',
|
|
||||||
data: {
|
|
||||||
action: 'hvac_zoho_run_scheduled_sync',
|
|
||||||
nonce: hvacZoho.nonce
|
|
||||||
},
|
|
||||||
success: function (response) {
|
|
||||||
if (response.success) {
|
|
||||||
var result = response.data.result;
|
|
||||||
var html = '<div class="notice notice-success">';
|
|
||||||
|
|
||||||
if (result.events && result.events.staging_mode) {
|
|
||||||
html += '<h4>🔧 STAGING MODE - Simulation Complete</h4>';
|
|
||||||
html += '<p>No data was sent to Zoho CRM.</p>';
|
|
||||||
} else {
|
|
||||||
html += '<p><strong>✅ Scheduled sync completed!</strong></p>';
|
|
||||||
}
|
|
||||||
|
|
||||||
html += '<ul>';
|
|
||||||
html += '<li>Total synced: ' + (result.total_synced || 0) + '</li>';
|
|
||||||
html += '<li>Total failed: ' + (result.total_failed || 0) + '</li>';
|
|
||||||
html += '<li>Duration: ' + (result.duration_seconds || 0) + ' seconds</li>';
|
|
||||||
html += '</ul>';
|
|
||||||
|
|
||||||
// Show details per type
|
|
||||||
html += '<details><summary>Details by type</summary><ul>';
|
|
||||||
['events', 'users', 'attendees', 'rsvps', 'purchases'].forEach(function (type) {
|
|
||||||
if (result[type]) {
|
|
||||||
html += '<li><strong>' + type + ':</strong> ' +
|
|
||||||
(result[type].synced || 0) + ' synced, ' +
|
|
||||||
(result[type].failed || 0) + ' failed</li>';
|
|
||||||
}
|
|
||||||
});
|
|
||||||
html += '</ul></details>';
|
|
||||||
|
|
||||||
html += '</div>';
|
|
||||||
$status.html(html);
|
|
||||||
} else {
|
|
||||||
$status.html('<div class="notice notice-error"><p>Sync failed: ' + response.data.message + '</p></div>');
|
|
||||||
}
|
|
||||||
},
|
|
||||||
error: function () {
|
|
||||||
$status.html('<div class="notice notice-error"><p>Error running scheduled sync</p></div>');
|
|
||||||
},
|
|
||||||
complete: function () {
|
|
||||||
$button.prop('disabled', false).text('🔄 Run Sync Now');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
// =====================================================
|
|
||||||
// Diagnostic Test Handler
|
|
||||||
// =====================================================
|
|
||||||
$('#diagnostic-test').on('click', function () {
|
|
||||||
var $button = $(this);
|
|
||||||
$button.prop('disabled', true).text('Testing...');
|
|
||||||
|
|
||||||
// Remove existing notices
|
|
||||||
$('.notice').remove();
|
|
||||||
|
|
||||||
// Test 1: Simple GET
|
|
||||||
var runSimpleTest = function () {
|
|
||||||
return $.ajax({
|
|
||||||
url: hvacZoho.ajaxUrl,
|
|
||||||
method: 'POST',
|
|
||||||
data: {
|
|
||||||
action: 'hvac_zoho_simple_test'
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
// Test 2: Payload Test (simulates credentials)
|
|
||||||
var runPayloadTest = function () {
|
|
||||||
var fakeId = '1000.' + new Array(20).join('a');
|
|
||||||
var fakeSecret = new Array(30).join('b');
|
|
||||||
|
|
||||||
return $.ajax({
|
|
||||||
url: hvacZoho.ajaxUrl,
|
|
||||||
method: 'POST',
|
|
||||||
data: {
|
|
||||||
action: 'hvac_zoho_simple_test',
|
|
||||||
test_payload: 'SIMULATED_CREDENTIALS',
|
|
||||||
zoho_client_id: fakeId,
|
|
||||||
zoho_client_secret: fakeSecret
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
// Execute tests sequence
|
|
||||||
runSimpleTest()
|
|
||||||
.then(function (response) {
|
|
||||||
if (response.success) {
|
|
||||||
console.log('Simple test passed');
|
|
||||||
return runPayloadTest();
|
|
||||||
} else {
|
|
||||||
return $.Deferred().reject({ status: 200, statusText: 'OK', responseJSON: response });
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.then(function (response) {
|
|
||||||
if (response.success) {
|
|
||||||
// Success!
|
|
||||||
var successHtml = '<div class="notice notice-success is-dismissible">' +
|
|
||||||
'<p><strong>✅ Diagnostic Test Passed</strong></p>' +
|
|
||||||
'<p>AJAX requests are working correctly. No WAF blocking detected for credential-like data.</p>' +
|
|
||||||
'</div>';
|
|
||||||
$('h1').after(successHtml);
|
|
||||||
} else {
|
|
||||||
return $.Deferred().reject({ status: 200, statusText: 'OK', responseJSON: response });
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.fail(function (xhr) {
|
|
||||||
var errorHtml = '<div class="notice notice-error is-dismissible">' +
|
|
||||||
'<p><strong>❌ Diagnostic Test Failed</strong></p>';
|
|
||||||
|
|
||||||
if (xhr.status === 400 || xhr.status === 403) {
|
|
||||||
errorHtml += '<p><strong>WAF Blocking Detected!</strong></p>';
|
|
||||||
errorHtml += '<p>The server returned ' + xhr.status + ' when sending data.</p>';
|
|
||||||
} else {
|
|
||||||
errorHtml += '<p>Status: ' + (xhr.status || 'Unknown') + '</p>';
|
|
||||||
if (xhr.responseJSON && xhr.responseJSON.data && xhr.responseJSON.data.message) {
|
|
||||||
errorHtml += '<p>Message: ' + xhr.responseJSON.data.message + '</p>';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
errorHtml += '</div>';
|
|
||||||
$('h1').after(errorHtml);
|
|
||||||
})
|
|
||||||
.always(function () {
|
|
||||||
$button.prop('disabled', false).text('🏥 Run Diagnostic Test');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
@ -54,11 +54,19 @@ class HVAC_Find_Trainer_Assets {
|
||||||
* Initialize WordPress hooks
|
* Initialize WordPress hooks
|
||||||
*/
|
*/
|
||||||
private function init_hooks() {
|
private function init_hooks() {
|
||||||
// Use proper WordPress hook system
|
// CRITICAL: Don't add asset loading hooks for Safari browsers
|
||||||
|
// Let HVAC_Scripts_Styles handle Safari minimal loading
|
||||||
|
if ($this->browser_detection->is_safari_browser()) {
|
||||||
|
error_log('[HVAC Find Trainer Assets] Safari detected - skipping asset hooks to prevent resource cascade');
|
||||||
|
// Only add footer scripts for MapGeo integration
|
||||||
|
add_action('wp_footer', [$this, 'add_find_trainer_inline_scripts']);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use proper WordPress hook system for non-Safari browsers
|
||||||
add_action('wp_enqueue_scripts', [$this, 'enqueue_find_trainer_assets']);
|
add_action('wp_enqueue_scripts', [$this, 'enqueue_find_trainer_assets']);
|
||||||
add_action('wp_footer', [$this, 'add_find_trainer_inline_scripts']);
|
add_action('wp_footer', [$this, 'add_find_trainer_inline_scripts']);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if current page is find-a-trainer
|
* Check if current page is find-a-trainer
|
||||||
|
|
|
||||||
|
|
@ -66,7 +66,7 @@ class HVAC_MapGeo_Safety {
|
||||||
'hvac-mapgeo-safety',
|
'hvac-mapgeo-safety',
|
||||||
HVAC_PLUGIN_URL . 'assets/js/mapgeo-safety.js',
|
HVAC_PLUGIN_URL . 'assets/js/mapgeo-safety.js',
|
||||||
array(),
|
array(),
|
||||||
HVAC_PLUGIN_VERSION . '.fix1',
|
HVAC_PLUGIN_VERSION,
|
||||||
false // Load in head to catch errors early
|
false // Load in head to catch errors early
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
||||||
211
includes/zoho/class-zoho-admin.php
Normal file
211
includes/zoho/class-zoho-admin.php
Normal file
|
|
@ -0,0 +1,211 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Zoho CRM Admin Interface
|
||||||
|
*
|
||||||
|
* Provides WordPress admin interface for Zoho credential management
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (!defined('ABSPATH')) {
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
class HVAC_Zoho_Admin {
|
||||||
|
|
||||||
|
public function __construct() {
|
||||||
|
add_action('admin_menu', array($this, 'add_admin_menu'));
|
||||||
|
add_action('admin_init', array($this, 'handle_auth_callback'));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add menu item to WordPress admin
|
||||||
|
*/
|
||||||
|
public function add_admin_menu() {
|
||||||
|
add_submenu_page(
|
||||||
|
'edit.php?post_type=tribe_events',
|
||||||
|
'Zoho CRM Integration',
|
||||||
|
'Zoho CRM',
|
||||||
|
'manage_options',
|
||||||
|
'hvac-zoho-crm',
|
||||||
|
array($this, 'admin_page')
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle OAuth callback
|
||||||
|
*/
|
||||||
|
public function handle_auth_callback() {
|
||||||
|
if (isset($_GET['page']) && $_GET['page'] === 'hvac-zoho-crm' && isset($_GET['code'])) {
|
||||||
|
$auth = new HVAC_Zoho_CRM_Auth();
|
||||||
|
|
||||||
|
if ($auth->exchange_code_for_tokens($_GET['code'])) {
|
||||||
|
add_settings_error(
|
||||||
|
'hvac_zoho_messages',
|
||||||
|
'hvac_zoho_auth_success',
|
||||||
|
'Successfully connected to Zoho CRM!',
|
||||||
|
'success'
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
add_settings_error(
|
||||||
|
'hvac_zoho_messages',
|
||||||
|
'hvac_zoho_auth_error',
|
||||||
|
'Failed to connect to Zoho CRM. Please check your credentials.',
|
||||||
|
'error'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Redirect to remove code from URL
|
||||||
|
wp_redirect(admin_url('edit.php?post_type=tribe_events&page=hvac-zoho-crm'));
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Display admin page
|
||||||
|
*/
|
||||||
|
public function admin_page() {
|
||||||
|
?>
|
||||||
|
<div class="wrap">
|
||||||
|
<h1>Zoho CRM Integration</h1>
|
||||||
|
|
||||||
|
<?php settings_errors('hvac_zoho_messages'); ?>
|
||||||
|
|
||||||
|
<?php
|
||||||
|
// Check if config file exists
|
||||||
|
$config_file = plugin_dir_path(dirname(__FILE__)) . 'zoho/zoho-config.php';
|
||||||
|
$config_exists = file_exists($config_file);
|
||||||
|
|
||||||
|
if (!$config_exists):
|
||||||
|
?>
|
||||||
|
<div class="notice notice-warning">
|
||||||
|
<p>Zoho CRM configuration file not found. Please follow the setup instructions below.</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h2>Setup Instructions</h2>
|
||||||
|
<ol>
|
||||||
|
<li>
|
||||||
|
<strong>Register your application in Zoho:</strong>
|
||||||
|
<a href="https://api-console.zoho.com/" target="_blank">Go to Zoho API Console</a>
|
||||||
|
</li>
|
||||||
|
<li>Create a new Server-based Application</li>
|
||||||
|
<li>Set redirect URI to: <code><?php echo admin_url('edit.php?post_type=tribe_events&page=hvac-zoho-crm'); ?></code></li>
|
||||||
|
<li>Copy your Client ID and Client Secret</li>
|
||||||
|
<li>Run the setup helper script from command line:
|
||||||
|
<pre>cd <?php echo plugin_dir_path(dirname(__FILE__)); ?>zoho
|
||||||
|
php setup-helper.php</pre>
|
||||||
|
</li>
|
||||||
|
</ol>
|
||||||
|
|
||||||
|
<?php else: ?>
|
||||||
|
|
||||||
|
<?php
|
||||||
|
// Load configuration
|
||||||
|
require_once $config_file;
|
||||||
|
$auth = new HVAC_Zoho_CRM_Auth();
|
||||||
|
|
||||||
|
// Test connection
|
||||||
|
$org_info = $auth->make_api_request('/crm/v2/org');
|
||||||
|
$connected = !is_wp_error($org_info) && isset($org_info['org']);
|
||||||
|
?>
|
||||||
|
|
||||||
|
<?php if ($connected): ?>
|
||||||
|
<div class="notice notice-success">
|
||||||
|
<p>✓ Connected to Zoho CRM</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h2>Organization Information</h2>
|
||||||
|
<table class="form-table">
|
||||||
|
<tr>
|
||||||
|
<th>Organization Name</th>
|
||||||
|
<td><?php echo esc_html($org_info['org'][0]['company_name']); ?></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>Organization ID</th>
|
||||||
|
<td><?php echo esc_html($org_info['org'][0]['id']); ?></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>Time Zone</th>
|
||||||
|
<td><?php echo esc_html($org_info['org'][0]['time_zone']); ?></td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<h2>Integration Status</h2>
|
||||||
|
<?php $this->display_integration_status(); ?>
|
||||||
|
|
||||||
|
<h2>Actions</h2>
|
||||||
|
<p>
|
||||||
|
<a href="<?php echo wp_nonce_url(admin_url('edit.php?post_type=tribe_events&page=hvac-zoho-crm&action=test_sync'), 'test_sync'); ?>"
|
||||||
|
class="button button-primary">Test Sync</a>
|
||||||
|
<a href="<?php echo wp_nonce_url(admin_url('edit.php?post_type=tribe_events&page=hvac-zoho-crm&action=create_fields'), 'create_fields'); ?>"
|
||||||
|
class="button">Create Custom Fields</a>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<?php else: ?>
|
||||||
|
<div class="notice notice-error">
|
||||||
|
<p>✗ Not connected to Zoho CRM</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h2>Reconnect to Zoho</h2>
|
||||||
|
<p>Click the button below to authorize this application with Zoho CRM:</p>
|
||||||
|
<p>
|
||||||
|
<a href="<?php echo esc_url($auth->get_authorization_url()); ?>"
|
||||||
|
class="button button-primary">Connect to Zoho CRM</a>
|
||||||
|
</p>
|
||||||
|
<?php endif; ?>
|
||||||
|
|
||||||
|
<?php endif; ?>
|
||||||
|
</div>
|
||||||
|
<?php
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Display integration status
|
||||||
|
*/
|
||||||
|
private function display_integration_status() {
|
||||||
|
?>
|
||||||
|
<table class="widefat striped">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Module</th>
|
||||||
|
<th>Fields Configured</th>
|
||||||
|
<th>Last Sync</th>
|
||||||
|
<th>Status</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td>Campaigns (Events)</td>
|
||||||
|
<td><?php echo $this->check_custom_fields('Campaigns'); ?></td>
|
||||||
|
<td><?php echo get_option('hvac_zoho_last_campaign_sync', 'Never'); ?></td>
|
||||||
|
<td><span class="dashicons dashicons-yes-alt" style="color: green;"></span></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Contacts (Users)</td>
|
||||||
|
<td><?php echo $this->check_custom_fields('Contacts'); ?></td>
|
||||||
|
<td><?php echo get_option('hvac_zoho_last_contact_sync', 'Never'); ?></td>
|
||||||
|
<td><span class="dashicons dashicons-yes-alt" style="color: green;"></span></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Invoices (Orders)</td>
|
||||||
|
<td><?php echo $this->check_custom_fields('Invoices'); ?></td>
|
||||||
|
<td><?php echo get_option('hvac_zoho_last_invoice_sync', 'Never'); ?></td>
|
||||||
|
<td><span class="dashicons dashicons-yes-alt" style="color: green;"></span></td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
<?php
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if custom fields exist
|
||||||
|
*/
|
||||||
|
private function check_custom_fields($module) {
|
||||||
|
// This would actually check via API if the custom fields exist
|
||||||
|
// For now, return a placeholder
|
||||||
|
return '<span style="color: orange;">Pending</span>';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize admin interface
|
||||||
|
if (is_admin()) {
|
||||||
|
new HVAC_Zoho_Admin();
|
||||||
|
}
|
||||||
|
|
@ -203,83 +203,13 @@ class HVAC_Zoho_CRM_Auth {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Make authenticated API request
|
|
||||||
*/
|
|
||||||
/**
|
|
||||||
* Check if we are in staging mode
|
|
||||||
*
|
|
||||||
* @return bool True if in staging mode
|
|
||||||
*/
|
|
||||||
public static function is_staging_mode() {
|
|
||||||
// 1. Allow forcing production mode via constant
|
|
||||||
if (defined('HVAC_ZOHO_PRODUCTION_MODE') && HVAC_ZOHO_PRODUCTION_MODE) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 2. Allow forcing staging mode via constant
|
|
||||||
if (defined('HVAC_ZOHO_STAGING_MODE') && HVAC_ZOHO_STAGING_MODE) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
$site_url = get_site_url();
|
|
||||||
|
|
||||||
// 3. Check for specific staging domains or keywords
|
|
||||||
if (strpos($site_url, 'staging') !== false ||
|
|
||||||
strpos($site_url, 'dev') !== false ||
|
|
||||||
strpos($site_url, 'test') !== false ||
|
|
||||||
strpos($site_url, 'cloudwaysapps.com') !== false) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 4. Default check: Production only on upskillhvac.com
|
|
||||||
return strpos($site_url, 'upskillhvac.com') === false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get details about how the mode was determined (for debugging)
|
|
||||||
*
|
|
||||||
* @return array Debug information
|
|
||||||
*/
|
|
||||||
public static function get_debug_mode_info() {
|
|
||||||
$info = array(
|
|
||||||
'site_url' => get_site_url(),
|
|
||||||
'is_staging' => self::is_staging_mode(),
|
|
||||||
'forced_production' => defined('HVAC_ZOHO_PRODUCTION_MODE') && HVAC_ZOHO_PRODUCTION_MODE,
|
|
||||||
'forced_staging' => defined('HVAC_ZOHO_STAGING_MODE') && HVAC_ZOHO_STAGING_MODE,
|
|
||||||
'detection_logic' => array()
|
|
||||||
);
|
|
||||||
|
|
||||||
// Replicate logic to show which rule matched
|
|
||||||
if ($info['forced_production']) {
|
|
||||||
$info['detection_logic'][] = 'Forced PRODUCTION via HVAC_ZOHO_PRODUCTION_MODE constant';
|
|
||||||
} elseif ($info['forced_staging']) {
|
|
||||||
$info['detection_logic'][] = 'Forced STAGING via HVAC_ZOHO_STAGING_MODE constant';
|
|
||||||
} else {
|
|
||||||
$site_url = $info['site_url'];
|
|
||||||
if (strpos($site_url, 'staging') !== false) $info['detection_logic'][] = 'Matched "staging" in URL';
|
|
||||||
if (strpos($site_url, 'dev') !== false) $info['detection_logic'][] = 'Matched "dev" in URL';
|
|
||||||
if (strpos($site_url, 'test') !== false) $info['detection_logic'][] = 'Matched "test" in URL';
|
|
||||||
if (strpos($site_url, 'cloudwaysapps.com') !== false) $info['detection_logic'][] = 'Matched "cloudwaysapps.com" in URL';
|
|
||||||
|
|
||||||
if (empty($info['detection_logic'])) {
|
|
||||||
if (strpos($site_url, 'upskillhvac.com') === false) {
|
|
||||||
$info['detection_logic'][] = 'Default STAGING: URL does not contain "upskillhvac.com"';
|
|
||||||
} else {
|
|
||||||
$info['detection_logic'][] = 'Default PRODUCTION: URL contains "upskillhvac.com"';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $info;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Make authenticated API request
|
* Make authenticated API request
|
||||||
*/
|
*/
|
||||||
public function make_api_request($endpoint, $method = 'GET', $data = null) {
|
public function make_api_request($endpoint, $method = 'GET', $data = null) {
|
||||||
// Check if we're in staging mode
|
// Check if we're in staging mode
|
||||||
$is_staging = self::is_staging_mode();
|
$site_url = get_site_url();
|
||||||
|
$is_staging = strpos($site_url, 'upskillhvac.com') === false;
|
||||||
|
|
||||||
// In staging mode, only allow read operations, no writes
|
// In staging mode, only allow read operations, no writes
|
||||||
if ($is_staging && in_array($method, array('POST', 'PUT', 'DELETE', 'PATCH'))) {
|
if ($is_staging && in_array($method, array('POST', 'PUT', 'DELETE', 'PATCH'))) {
|
||||||
|
|
@ -328,8 +258,7 @@ class HVAC_Zoho_CRM_Auth {
|
||||||
return new WP_Error('no_token', $error_message);
|
return new WP_Error('no_token', $error_message);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update to v6 API (v2 is deprecated)
|
$url = 'https://www.zohoapis.com/crm/v2' . $endpoint;
|
||||||
$url = 'https://www.zohoapis.com/crm/v6' . $endpoint;
|
|
||||||
|
|
||||||
// Log the request details
|
// Log the request details
|
||||||
$this->log_debug('Making ' . $method . ' request to: ' . $url);
|
$this->log_debug('Making ' . $method . ' request to: ' . $url);
|
||||||
|
|
@ -398,8 +327,7 @@ class HVAC_Zoho_CRM_Auth {
|
||||||
return array(
|
return array(
|
||||||
'error' => $error_message,
|
'error' => $error_message,
|
||||||
'code' => 'JSON_PARSE_ERROR',
|
'code' => 'JSON_PARSE_ERROR',
|
||||||
'details' => 'Raw response: ' . substr($body, 0, 500),
|
'details' => 'Raw response: ' . substr($body, 0, 255) . (strlen($body) > 255 ? '...' : '')
|
||||||
'request_payload' => isset($args['body']) ? $args['body'] : 'No body'
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -416,7 +344,6 @@ class HVAC_Zoho_CRM_Auth {
|
||||||
// Add HTTP error information to the response
|
// Add HTTP error information to the response
|
||||||
$data['http_status'] = $status_code;
|
$data['http_status'] = $status_code;
|
||||||
$data['error'] = $error_message;
|
$data['error'] = $error_message;
|
||||||
$data['request_payload'] = isset($args['body']) ? $args['body'] : 'No body';
|
|
||||||
|
|
||||||
// Extract more detailed error information if available
|
// Extract more detailed error information if available
|
||||||
if (isset($data['code'])) {
|
if (isset($data['code'])) {
|
||||||
|
|
@ -479,7 +406,7 @@ class HVAC_Zoho_CRM_Auth {
|
||||||
/**
|
/**
|
||||||
* Log debug messages
|
* Log debug messages
|
||||||
*/
|
*/
|
||||||
public function log_debug($message) {
|
private function log_debug($message) {
|
||||||
// Sanitize message to remove sensitive data
|
// Sanitize message to remove sensitive data
|
||||||
$sanitized = $this->sanitize_log_message($message);
|
$sanitized = $this->sanitize_log_message($message);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -261,15 +261,11 @@ class HVAC_Zoho_Scheduled_Sync {
|
||||||
|
|
||||||
// Calculate totals
|
// Calculate totals
|
||||||
$total_synced = 0;
|
$total_synced = 0;
|
||||||
$total_skipped = 0;
|
|
||||||
$total_failed = 0;
|
$total_failed = 0;
|
||||||
foreach (array('events', 'users', 'attendees', 'rsvps', 'purchases') as $type) {
|
foreach (array('events', 'users', 'attendees', 'rsvps', 'purchases') as $type) {
|
||||||
if (isset($results[$type]['synced'])) {
|
if (isset($results[$type]['synced'])) {
|
||||||
$total_synced += $results[$type]['synced'];
|
$total_synced += $results[$type]['synced'];
|
||||||
}
|
}
|
||||||
if (isset($results[$type]['skipped'])) {
|
|
||||||
$total_skipped += $results[$type]['skipped'];
|
|
||||||
}
|
|
||||||
if (isset($results[$type]['failed'])) {
|
if (isset($results[$type]['failed'])) {
|
||||||
$total_failed += $results[$type]['failed'];
|
$total_failed += $results[$type]['failed'];
|
||||||
}
|
}
|
||||||
|
|
@ -278,14 +274,13 @@ class HVAC_Zoho_Scheduled_Sync {
|
||||||
$results['completed_at'] = date('Y-m-d H:i:s');
|
$results['completed_at'] = date('Y-m-d H:i:s');
|
||||||
$results['duration_seconds'] = time() - $start_time;
|
$results['duration_seconds'] = time() - $start_time;
|
||||||
$results['total_synced'] = $total_synced;
|
$results['total_synced'] = $total_synced;
|
||||||
$results['total_skipped'] = $total_skipped;
|
|
||||||
$results['total_failed'] = $total_failed;
|
$results['total_failed'] = $total_failed;
|
||||||
|
|
||||||
// Save last result
|
// Save last result
|
||||||
update_option(self::OPTION_LAST_RESULT, $results);
|
update_option(self::OPTION_LAST_RESULT, $results);
|
||||||
|
|
||||||
if (class_exists('HVAC_Logger')) {
|
if (class_exists('HVAC_Logger')) {
|
||||||
HVAC_Logger::info("Scheduled sync completed: {$total_synced} synced, {$total_skipped} skipped, {$total_failed} failed", 'ZohoScheduledSync');
|
HVAC_Logger::info("Scheduled sync completed: {$total_synced} synced, {$total_failed} failed", 'ZohoScheduledSync');
|
||||||
}
|
}
|
||||||
|
|
||||||
return $results;
|
return $results;
|
||||||
|
|
@ -305,7 +300,6 @@ class HVAC_Zoho_Scheduled_Sync {
|
||||||
$aggregated = array(
|
$aggregated = array(
|
||||||
'total' => 0,
|
'total' => 0,
|
||||||
'synced' => 0,
|
'synced' => 0,
|
||||||
'skipped' => 0,
|
|
||||||
'failed' => 0,
|
'failed' => 0,
|
||||||
'errors' => array(),
|
'errors' => array(),
|
||||||
);
|
);
|
||||||
|
|
@ -317,7 +311,6 @@ class HVAC_Zoho_Scheduled_Sync {
|
||||||
// Aggregate results
|
// Aggregate results
|
||||||
$aggregated['total'] = $result['total'] ?? 0;
|
$aggregated['total'] = $result['total'] ?? 0;
|
||||||
$aggregated['synced'] += $result['synced'] ?? 0;
|
$aggregated['synced'] += $result['synced'] ?? 0;
|
||||||
$aggregated['skipped'] += $result['skipped'] ?? 0;
|
|
||||||
$aggregated['failed'] += $result['failed'] ?? 0;
|
$aggregated['failed'] += $result['failed'] ?? 0;
|
||||||
|
|
||||||
if (!empty($result['errors'])) {
|
if (!empty($result['errors'])) {
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
Loading…
Reference in a new issue