| @@ -439,8 +439,22 @@ | ||
| 439 | 439 | update_option('mxchat_video_embed_enabled', $vce_value); |
| 440 | 440 | wp_send_json_success(['message' => esc_html__('Setting saved', 'mxchat')]); |
| 441 | 441 | return; |
| 442 | 442 | |
| 443 | + // Page-cache purge on settings save (plan b76ed6, Support Ticket 468). | |
| 444 | + // STANDALONE option, same pattern. Default ON — the purge already ships | |
| 445 | + // (3.2.9), so this is an opt-OUT for large sites. Switching it off also | |
| 446 | + // drops a deferred purge the debounce may have scheduled seconds ago, | |
| 447 | + // so "off" takes effect at once rather than after one more purge. | |
| 448 | + case 'mxchat_cache_purge_enabled': | |
| 449 | + $cpe_value = ($value === 'on' || $value === '1') ? 'on' : 'off'; | |
| 450 | + update_option('mxchat_cache_purge_enabled', $cpe_value); | |
| 451 | + if ($cpe_value === 'off' && class_exists('MxChat_Cache_Purge')) { | |
| 452 | + wp_clear_scheduled_hook(MxChat_Cache_Purge::DEFERRED_EVENT); | |
| 453 | + } | |
| 454 | + wp_send_json_success(['message' => esc_html__('Setting saved', 'mxchat')]); | |
| 455 | + return; | |
| 456 | + | |
| 443 | 457 | // Clamped to the same 20-95 the field advertises. An out-of-range or |
| 444 | 458 | // non-numeric POST is corrected rather than refused, and the corrected |
| 445 | 459 | // value is echoed back so the field can reconcile — a silently stored |
| 446 | 460 | // 0 here would put a video on every answer, which is the bug. |
| @@ -613,8 +627,29 @@ | ||
| 613 | 627 | //error_log('MXChat Save: Processing live_agent_status'); |
| 614 | 628 | // Set the new value |
| 615 | 629 | $options[$field_name] = ($value === 'on') ? 'on' : 'off'; |
| 616 | 630 | break; |
| 631 | + // Shared handoff channel (plan 1a2666): re-probe the channel's privacy | |
| 632 | + // at configuration time so the settings screen can warn about private | |
| 633 | + // channels (their inbound events arrive as message.groups, which the | |
| 634 | + // documented app setup never subscribes to). Only id-shaped values can | |
| 635 | + // be checked before the first handoff resolves a #name — the handoff | |
| 636 | + // path probes those when it caches the resolved id. | |
| 637 | + case 'live_agent_shared_channel': | |
| 638 | + $options[$field_name] = sanitize_text_field($value); | |
| 639 | + delete_option('mxchat_slack_shared_channel_privacy'); | |
| 640 | + $shared_channel_target = ltrim(trim((string) $options[$field_name]), '#'); | |
| 641 | + if ($shared_channel_target !== '' && preg_match('/^[CG][A-Z0-9]{6,}$/', $shared_channel_target)) { | |
| 642 | + if (!class_exists('MxChat_Integrator')) { | |
| 643 | + require_once plugin_dir_path(dirname(__FILE__)) . 'includes/class-mxchat-integrator.php'; | |
| 644 | + } | |
| 645 | + MxChat_Integrator::mxchat_probe_slack_channel_privacy( | |
| 646 | + $options['live_agent_bot_token'] ?? '', | |
| 647 | + $shared_channel_target, | |
| 648 | + trim((string) $options[$field_name]) | |
| 649 | + ); | |
| 650 | + } | |
| 651 | + break; | |
| 617 | 652 | // Webhook handoff destination (plan d88e22). Status normalized like the |
| 618 | 653 | // other channel toggles; the URL is refused outright when it isn't |
| 619 | 654 | // https so the admin hears about it at save time instead of the |
| 620 | 655 | // handoff silently never firing. |
| @@ -1036,8 +1071,36 @@ | ||
| 1036 | 1071 | if ($field_name === 'mxchat_pinecone_host') { |
| 1037 | 1072 | $new_value = str_replace(['https://', 'http://'], '', $new_value); |
| 1038 | 1073 | } |
| 1039 | 1074 | break; |
| 1075 | + case 'mxchat_pinecone_index_type': | |
| 1076 | + // 362c31: document only once the host has been checked (see sanitize_pinecone_settings). | |
| 1077 | + $new_value = ($value === 'document') ? 'document' : 'vector'; | |
| 1078 | + if ($new_value === 'document' && strtolower(trim((string) ($current_options['mxchat_pinecone_host'] ?? ''), '/')) !== strtolower((string) ($current_options['mxchat_pinecone_docs_verified_host'] ?? ''))) { | |
| 1079 | + wp_send_json_error(['message' => esc_html__('Check the document index host first (Check index or Create index for me).', 'mxchat')]); | |
| 1080 | + } | |
| 1081 | + // 3e83e4: same gate as the form save — no switch onto a half-copied index. | |
| 1082 | + if ($new_value === 'document' && (($current_options['mxchat_pinecone_index_type'] ?? 'vector') !== 'document') && class_exists('MxChat_Pinecone_Documents')) { | |
| 1083 | + $running = MxChat_Pinecone_Documents::migration_blocks_switch((string) ($current_options['mxchat_pinecone_host'] ?? '')); | |
| 1084 | + if ($running !== null) { | |
| 1085 | + wp_send_json_error(['message' => MxChat_Pinecone_Documents::switch_blocked_message($running)]); | |
| 1086 | + } | |
| 1087 | + } | |
| 1088 | + break; | |
| 1089 | + case 'mxchat_pinecone_vector_host': | |
| 1090 | + $new_value = trim(str_replace(['https://', 'http://'], '', sanitize_text_field($value)), '/'); | |
| 1091 | + break; | |
| 1092 | + case 'mxchat_pinecone_vector_index': | |
| 1093 | + case 'mxchat_pinecone_docs_region': | |
| 1094 | + $new_value = sanitize_text_field($value); | |
| 1095 | + break; | |
| 1096 | + case 'mxchat_pinecone_docs_cloud': | |
| 1097 | + $new_value = in_array($value, array('aws', 'gcp', 'azure'), true) ? $value : 'aws'; | |
| 1098 | + break; | |
| 1099 | + case 'mxchat_pinecone_docs_language': | |
| 1100 | + $lang_value = sanitize_key($value); | |
| 1101 | + $new_value = (class_exists('MxChat_Pinecone_Documents') && array_key_exists($lang_value, MxChat_Pinecone_Documents::languages())) ? $lang_value : 'en'; | |
| 1102 | + break; | |
| 1040 | 1103 | case 'mxchat_pinecone_top_k': |
| 1041 | 1104 | // d0cae1: out-of-range and junk normalize to the default 50 — |
| 1042 | 1105 | // same clamp the read site applies. |
| 1043 | 1106 | $top_k = absint($value); |
| @@ -1478,9 +1541,10 @@ | ||
| 1478 | 1541 | } |
| 1479 | 1542 | |
| 1480 | 1543 | $product_id = 'MxChatPRO'; |
| 1481 | 1544 | $domain = parse_url(home_url(), PHP_URL_HOST); // Get the current domain |
| 1482 | - | |
| 1545 | + $was_active = (get_option('mxchat_license_status', 'inactive') === 'active'); | |
| 1546 | + | |
| 1483 | 1547 | // Call WooCommerce Software API for activation (not just validation) |
| 1484 | 1548 | $response = wp_remote_get( |
| 1485 | 1549 | add_query_arg( |
| 1486 | 1550 | array( |
| @@ -1526,9 +1590,16 @@ | ||
| 1526 | 1590 | update_option('mxchat_license_status', 'active'); |
| 1527 | 1591 | update_option('mxchat_pro_email', $customer_email); |
| 1528 | 1592 | update_option('mxchat_activation_key', $license_key); |
| 1529 | 1593 | delete_option('mxchat_license_error'); |
| 1530 | - | |
| 1594 | + | |
| 1595 | + // A fresh activation starts the licence domain check (c93ede) from a | |
| 1596 | + // clean slate: no grace streak carried over, first daily check at a | |
| 1597 | + // random time within the day. | |
| 1598 | + if (class_exists('MxChat_License_Check')) { | |
| 1599 | + MxChat_License_Check::reset(true); | |
| 1600 | + } | |
| 1601 | + | |
| 1531 | 1602 | // Also track on your website (this is your existing domain tracking) |
| 1532 | 1603 | $this->track_domain_on_website($license_key, $customer_email, $domain); |
| 1533 | 1604 | |
| 1534 | 1605 | wp_send_json_success(array('message' => esc_html__('License activated successfully', 'mxchat'))); |
| @@ -1535,9 +1606,17 @@ | ||
| 1535 | 1606 | } else { |
| 1536 | 1607 | $error_message = isset($data->error) ? $data->error : esc_html__('Activation failed', 'mxchat'); |
| 1537 | 1608 | update_option('mxchat_license_status', 'inactive'); |
| 1538 | 1609 | update_option('mxchat_license_error', $error_message); |
| 1539 | - | |
| 1610 | + | |
| 1611 | + // c93ede: a refusal by the licence owner (domain switched off, new sites | |
| 1612 | + // blocked) or a revoked key is an explicit "off" from mxchat.ai. Remember | |
| 1613 | + // who controls it so Pro & Extensions says so, and keep checking so the | |
| 1614 | + // owner's switch-on restores Pro without another click here. | |
| 1615 | + if (class_exists('MxChat_License_Check')) { | |
| 1616 | + MxChat_License_Check::note_activation_refusal(isset($data->code) ? (string) $data->code : '', (string) $error_message, $was_active); | |
| 1617 | + } | |
| 1618 | + | |
| 1540 | 1619 | //error_log('MxChat Activation failed: ' . $error_message); |
| 1541 | 1620 | wp_send_json_error($error_message); |
| 1542 | 1621 | } |
| 1543 | 1622 | } |
| @@ -1622,9 +1701,15 @@ | ||
| 1622 | 1701 | delete_option('mxchat_license_status'); |
| 1623 | 1702 | delete_option('mxchat_pro_email'); |
| 1624 | 1703 | delete_option('mxchat_activation_key'); |
| 1625 | 1704 | delete_option('mxchat_license_error'); |
| 1626 | - | |
| 1705 | + | |
| 1706 | + // Nothing left to check: drop the licence domain check's state and its | |
| 1707 | + // scheduled event (c93ede). | |
| 1708 | + if (class_exists('MxChat_License_Check')) { | |
| 1709 | + MxChat_License_Check::reset(false); | |
| 1710 | + } | |
| 1711 | + | |
| 1627 | 1712 | //error_log('MxChat deactivate: Local data cleared'); |
| 1628 | 1713 | |
| 1629 | 1714 | // Notify your website's API to properly deactivate |
| 1630 | 1715 | $response = wp_remote_post('https://mxchat.ai/mxchat-api/deactivate-license', array( |