Plugin Directory

Changeset 3343848


Ignore:
Timestamp:
08/13/2025 01:28:41 AM (6 months ago)
Author:
mxchat
Message:

Update to version 2.3.8: Fixed knowledgebase backslash issue, added optional name field to Require Email to Chat form, and improved Slack channel naming for live agent notifications.

Location:
mxchat-basic
Files:
96 added
12 edited

Legend:

Unmodified
Added
Removed
  • mxchat-basic/trunk/admin/class-ajax-handler.php

    r3335923 r3343848  
    4545    // ========================================
    4646
    47     /**
    48      * Validates and saves chat settings via AJAX request
    49      */
    50      public function mxchat_save_setting_callback() {
    51          check_ajax_referer('mxchat_save_setting_nonce');
    52          if (!current_user_can('manage_options')) {
    53              ('MXChat Save: Unauthorized access attempt');
    54              wp_send_json_error(['message' => esc_html__('Unauthorized', 'mxchat')]);
    55          }
    56 
    57          $name = isset($_POST['name']) ? $_POST['name'] : '';
    58          // Strip slashes from the value before saving
    59          $value = isset($_POST['value']) ? stripslashes($_POST['value']) : '';
    60 
    61          //error_log('MXChat Save: Processing field name: ' . $name);
    62          //error_log('MXChat Save: Field value: ' . $value);
    63 
    64          if (empty($name)) {
    65              //error_log('MXChat Save: Empty field name detected');
    66              wp_send_json_error(['message' => esc_html__('Invalid field name', 'mxchat')]);
    67          }
    68 
    69          // Load the full options array
    70          $options = get_option('mxchat_options', []);
    71          //error_log('MXChat Save: Current options array: ' . print_r($options, true));
    72 
    73          // Handle special cases
    74          switch ($name) {
    75              case 'additional_popular_questions':
    76                  //error_log('MXChat Save: Processing additional_popular_questions');
    77                  $questions = json_decode($value, true); // No need for stripslashes here
    78                  if (is_array($questions)) {
    79                      $options[$name] = $questions;
    80                      // Also update old option for backwards compatibility
    81                      update_option('additional_popular_questions', $questions);
    82                      //error_log('MXChat Save: Saved ' . count($questions) . ' additional questions');
    83                  } else {
    84                      //error_log('MXChat Save: Failed to decode questions JSON');
    85                  }
    86                  break;
    87              case 'email_blocker_header_content':
    88                  //error_log('MXChat Save: Processing email_blocker_header_content');
    89                  // Allow HTML content but sanitize it safely
    90                  $options[$name] = wp_kses_post($value);
    91                  break;
    92              case 'similarity_threshold':
    93                  //error_log('MXChat Save: Processing similarity_threshold');
    94                  // Save to the options array
    95                  $options[$name] = $value;
    96                  break;
    97              case 'user_message_bg_color':
    98              case 'user_message_font_color':
    99              case 'bot_message_bg_color':
    100              case 'bot_message_font_color':
    101              case 'top_bar_bg_color':
    102              case 'send_button_font_color':
    103              case 'chatbot_background_color':
    104              case 'icon_color':
    105              case 'chat_input_font_color':
    106              case 'live_agent_message_bg_color':
    107              case 'live_agent_message_font_color':
    108              case 'mode_indicator_bg_color':
    109              case 'mode_indicator_font_color':
    110              case 'toolbar_icon_color':
    111             case 'quick_questions_toggle_color':
    112                  //error_log('MXChat Save: Processing color value: ' . $name);
    113                  // Store color values directly
    114                  $options[$name] = $value;
    115                  break;
    116              case 'live_agent_status':
    117                  //error_log('MXChat Save: Processing live_agent_status');
    118                  // Set the new value
    119                  $options[$name] = ($value === 'on') ? 'on' : 'off';
    120                  break;
    121              case 'enable_woocommerce_integration':
    122                  //error_log('MXChat Save: Processing enable_woocommerce_integration');
    123                  // Handle values that used to be 1/0
    124                  $options[$name] = ($value === 'on' || $value === '1') ? 'on' : 'off';
    125                  break;
    126              default:
    127                  // First check for rate limits settings
    128                  if (strpos($name, 'mxchat_options[rate_limits]') !== false) {
    129                      //error_log('MXChat Save: Detected rate_limits field: ' . $name);
    130 
    131                      // Extract role ID and setting from the name
    132                      preg_match('/\[rate_limits\]\[(.*?)\]\[(.*?)\]/', $name, $matches);
    133                      //error_log('MXChat Save: Regex matches: ' . print_r($matches, true));
    134 
    135                      if (isset($matches[1]) && isset($matches[2])) {
    136                          $role_id = $matches[1];
    137                          $setting_key = $matches[2]; // limit, timeframe, or message
    138 
    139                          //error_log('MXChat Save: Role ID = ' . $role_id . ', Setting Key = ' . $setting_key);
    140 
    141                          // Initialize rate_limits if it doesn't exist
    142                          if (!isset($options['rate_limits'])) {
    143                             // //error_log('MXChat Save: Initializing rate_limits array');
    144                              $options['rate_limits'] = [];
    145                          }
    146 
    147                          // Initialize role settings if it doesn't exist
    148                          if (!isset($options['rate_limits'][$role_id])) {
    149                              //error_log('MXChat Save: Initializing rate_limits for role: ' . $role_id);
    150                              $options['rate_limits'][$role_id] = [
    151                                  'limit' => ($role_id === 'logged_out') ? '10' : '100',
    152                                  'timeframe' => 'daily',
    153                                  'message' => 'Rate limit exceeded. Please try again later.'
    154                              ];
    155                          }
    156 
    157                          // Update the specific setting
    158                          $options['rate_limits'][$role_id][$setting_key] = $value;
    159                          //error_log('MXChat Save: Updated rate_limits[' . $role_id . '][' . $setting_key . '] = ' . $value);
    160                      } else {
    161                          //error_log('MXChat Save: Failed to parse rate_limits pattern: ' . $name);
    162                      }
    163                  }
    164                  // Then check for role rate limits (old format)
    165                  else if (strpos($name, 'mxchat_options[role_rate_limits]') !== false) {
    166                      //error_log('MXChat Save: Processing role_rate_limits field: ' . $name);
    167                      // Extract role ID from the name
    168                      preg_match('/\[role_rate_limits\]\[(.*?)\]/', $name, $matches);
    169                      //error_log('MXChat Save: Regex matches: ' . print_r($matches, true));
    170 
    171                      if (isset($matches[1])) {
    172                          $role_id = $matches[1];
    173                          // Initialize role_rate_limits if it doesn't exist
    174                          if (!isset($options['role_rate_limits'])) {
    175                              //error_log('MXChat Save: Initializing role_rate_limits array');
    176                              $options['role_rate_limits'] = [];
    177                          }
    178                          // Update the specific role's rate limit
    179                          $options['role_rate_limits'][$role_id] = sanitize_text_field($value);
    180                          //error_log('MXChat Save: Updated role_rate_limits[' . $role_id . '] = ' . $value);
    181                      } else {
    182                          //error_log('MXChat Save: Failed to parse role_rate_limits pattern: ' . $name);
    183                      }
    184                  }
    185                  // Handle toggles
    186                 else if (strpos($name, 'toggle') !== false || in_array($name, [
    187                     'chat_persistence_toggle',
    188                     'privacy_toggle',
    189                     'complianz_toggle',
    190                     'chat_toolbar_toggle',
    191                     'show_pdf_upload_button',
    192                     'show_word_upload_button',
    193                     'enable_streaming_toggle',
    194                     'contextual_awareness_toggle' // Add this line
    195                 ])) {
    196                     //error_log('MXChat Save: Processing toggle: ' . $name);
    197                     $options[$name] = ($value === 'on') ? 'on' : 'off';
     47/**
     48 * Validates and saves chat settings via AJAX request
     49 */
     50public function mxchat_save_setting_callback() {
     51    check_ajax_referer('mxchat_save_setting_nonce');
     52    if (!current_user_can('manage_options')) {
     53        ('MXChat Save: Unauthorized access attempt');
     54        wp_send_json_error(['message' => esc_html__('Unauthorized', 'mxchat')]);
     55    }
     56
     57    $name = isset($_POST['name']) ? $_POST['name'] : '';
     58    // Strip slashes from the value before saving
     59    $value = isset($_POST['value']) ? stripslashes($_POST['value']) : '';
     60
     61    //error_log('MXChat Save: Processing field name: ' . $name);
     62    //error_log('MXChat Save: Field value: ' . $value);
     63
     64    if (empty($name)) {
     65        //error_log('MXChat Save: Empty field name detected');
     66        wp_send_json_error(['message' => esc_html__('Invalid field name', 'mxchat')]);
     67    }
     68
     69    // Load the full options array
     70    $options = get_option('mxchat_options', []);
     71    //error_log('MXChat Save: Current options array: ' . print_r($options, true));
     72
     73    // Handle special cases
     74    switch ($name) {
     75        case 'additional_popular_questions':
     76            //error_log('MXChat Save: Processing additional_popular_questions');
     77            $questions = json_decode($value, true); // No need for stripslashes here
     78            if (is_array($questions)) {
     79                $options[$name] = $questions;
     80                // Also update old option for backwards compatibility
     81                update_option('additional_popular_questions', $questions);
     82                //error_log('MXChat Save: Saved ' . count($questions) . ' additional questions');
     83            } else {
     84                //error_log('MXChat Save: Failed to decode questions JSON');
     85            }
     86            break;
     87        case 'email_blocker_header_content':
     88            //error_log('MXChat Save: Processing email_blocker_header_content');
     89            // Allow HTML content but sanitize it safely
     90            $options[$name] = wp_kses_post($value);
     91            break;
     92        case 'email_blocker_button_text':
     93            //error_log('MXChat Save: Processing email_blocker_button_text');
     94            $options[$name] = sanitize_text_field($value);
     95            break;
     96        case 'name_field_placeholder':
     97            //error_log('MXChat Save: Processing name_field_placeholder');
     98            $options[$name] = sanitize_text_field($value);
     99            break;
     100        case 'similarity_threshold':
     101            //error_log('MXChat Save: Processing similarity_threshold');
     102            // Save to the options array
     103            $options[$name] = $value;
     104            break;
     105        case 'user_message_bg_color':
     106        case 'user_message_font_color':
     107        case 'bot_message_bg_color':
     108        case 'bot_message_font_color':
     109        case 'top_bar_bg_color':
     110        case 'send_button_font_color':
     111        case 'chatbot_background_color':
     112        case 'icon_color':
     113        case 'chat_input_font_color':
     114        case 'live_agent_message_bg_color':
     115        case 'live_agent_message_font_color':
     116        case 'mode_indicator_bg_color':
     117        case 'mode_indicator_font_color':
     118        case 'toolbar_icon_color':
     119        case 'quick_questions_toggle_color':
     120            //error_log('MXChat Save: Processing color value: ' . $name);
     121            // Store color values directly
     122            $options[$name] = $value;
     123            break;
     124        case 'live_agent_status':
     125            //error_log('MXChat Save: Processing live_agent_status');
     126            // Set the new value
     127            $options[$name] = ($value === 'on') ? 'on' : 'off';
     128            break;
     129        case 'enable_woocommerce_integration':
     130            //error_log('MXChat Save: Processing enable_woocommerce_integration');
     131            // Handle values that used to be 1/0
     132            $options[$name] = ($value === 'on' || $value === '1') ? 'on' : 'off';
     133            break;
     134        default:
     135            // First check for rate limits settings
     136            if (strpos($name, 'mxchat_options[rate_limits]') !== false) {
     137                //error_log('MXChat Save: Detected rate_limits field: ' . $name);
     138
     139                // Extract role ID and setting from the name
     140                preg_match('/\[rate_limits\]\[(.*?)\]\[(.*?)\]/', $name, $matches);
     141                //error_log('MXChat Save: Regex matches: ' . print_r($matches, true));
     142
     143                if (isset($matches[1]) && isset($matches[2])) {
     144                    $role_id = $matches[1];
     145                    $setting_key = $matches[2]; // limit, timeframe, or message
     146
     147                    //error_log('MXChat Save: Role ID = ' . $role_id . ', Setting Key = ' . $setting_key);
     148
     149                    // Initialize rate_limits if it doesn't exist
     150                    if (!isset($options['rate_limits'])) {
     151                       // //error_log('MXChat Save: Initializing rate_limits array');
     152                        $options['rate_limits'] = [];
     153                    }
     154
     155                    // Initialize role settings if it doesn't exist
     156                    if (!isset($options['rate_limits'][$role_id])) {
     157                        //error_log('MXChat Save: Initializing rate_limits for role: ' . $role_id);
     158                        $options['rate_limits'][$role_id] = [
     159                            'limit' => ($role_id === 'logged_out') ? '10' : '100',
     160                            'timeframe' => 'daily',
     161                            'message' => 'Rate limit exceeded. Please try again later.'
     162                        ];
     163                    }
     164
     165                    // Update the specific setting
     166                    $options['rate_limits'][$role_id][$setting_key] = $value;
     167                    //error_log('MXChat Save: Updated rate_limits[' . $role_id . '][' . $setting_key . '] = ' . $value);
    198168                } else {
    199                      //error_log('MXChat Save: Processing standard field: ' . $name);
    200                      // Store all other values directly
    201                      $options[$name] = $value;
    202                  }
    203                  break;
    204          }
    205 
    206          // Save all updates to the options array
    207          $updated = update_option('mxchat_options', $options);
    208          //error_log('MXChat Save: Update result: ' . ($updated ? 'success' : 'unchanged') . ' for field: ' . $name);
    209          //error_log('MXChat Save: Updated options array: ' . print_r($options, true));
    210 
    211          // Always return success even if WordPress says nothing changed
    212          // (which happens when the value is the same as before)
    213          wp_send_json_success(['message' => esc_html__('Setting saved', 'mxchat')]);
    214      }
     169                    //error_log('MXChat Save: Failed to parse rate_limits pattern: ' . $name);
     170                }
     171            }
     172            // Then check for role rate limits (old format)
     173            else if (strpos($name, 'mxchat_options[role_rate_limits]') !== false) {
     174                //error_log('MXChat Save: Processing role_rate_limits field: ' . $name);
     175                // Extract role ID from the name
     176                preg_match('/\[role_rate_limits\]\[(.*?)\]/', $name, $matches);
     177                //error_log('MXChat Save: Regex matches: ' . print_r($matches, true));
     178
     179                if (isset($matches[1])) {
     180                    $role_id = $matches[1];
     181                    // Initialize role_rate_limits if it doesn't exist
     182                    if (!isset($options['role_rate_limits'])) {
     183                        //error_log('MXChat Save: Initializing role_rate_limits array');
     184                        $options['role_rate_limits'] = [];
     185                    }
     186                    // Update the specific role's rate limit
     187                    $options['role_rate_limits'][$role_id] = sanitize_text_field($value);
     188                    //error_log('MXChat Save: Updated role_rate_limits[' . $role_id . '] = ' . $value);
     189                } else {
     190                    //error_log('MXChat Save: Failed to parse role_rate_limits pattern: ' . $name);
     191                }
     192            }
     193            // Handle toggles
     194            else if (strpos($name, 'toggle') !== false || in_array($name, [
     195                'chat_persistence_toggle',
     196                'privacy_toggle',
     197                'complianz_toggle',
     198                'chat_toolbar_toggle',
     199                'show_pdf_upload_button',
     200                'show_word_upload_button',
     201                'enable_streaming_toggle',
     202                'contextual_awareness_toggle',
     203                'enable_email_block',
     204                'enable_name_field'
     205            ])) {
     206                //error_log('MXChat Save: Processing toggle: ' . $name);
     207                $options[$name] = ($value === 'on') ? 'on' : 'off';
     208            } else {
     209                //error_log('MXChat Save: Processing standard field: ' . $name);
     210                // Store all other values directly
     211                $options[$name] = $value;
     212            }
     213            break;
     214    }
     215
     216    // Save all updates to the options array
     217    $updated = update_option('mxchat_options', $options);
     218    //error_log('MXChat Save: Update result: ' . ($updated ? 'success' : 'unchanged') . ' for field: ' . $name);
     219    //error_log('MXChat Save: Updated options array: ' . print_r($options, true));
     220
     221    // Always return success even if WordPress says nothing changed
     222    // (which happens when the value is the same as before)
     223    wp_send_json_success(['message' => esc_html__('Setting saved', 'mxchat')]);
     224}
    215225
    216226
  • mxchat-basic/trunk/admin/class-knowledge-manager.php

    r3333920 r3343848  
    723723    // If we get here, nonce passed
    724724    error_log('Nonce verification PASSED');
    725 
    726          // Verify permissions
    727          if (!current_user_can('manage_options')) {
    728              wp_send_json_error(esc_html__('Permission denied.', 'mxchat'));
    729              return;
    730          }
    731 
    732          global $wpdb;
    733          $table_name = $wpdb->prefix . 'mxchat_system_prompt_content';
    734 
    735          // Validate and sanitize input data
    736          $prompt_id = isset($_POST['id']) ? absint($_POST['id']) : 0;
    737          $article_content = isset($_POST['article_content']) ? sanitize_textarea_field($_POST['article_content']) : '';
    738          $article_url = isset($_POST['article_url']) ? esc_url_raw($_POST['article_url']) : '';
    739 
    740          if ($prompt_id > 0 && !empty($article_content)) {
    741              // Re-generate the embedding vector for the updated content
    742              $embedding_vector = $this->mxchat_generate_embedding($article_content);
    743 
    744              if (is_array($embedding_vector)) {
    745                  // Serialize the embedding vector before storing it
    746                  $embedding_vector_serialized = serialize($embedding_vector);
    747 
    748                  // Update the prompt in the database
    749                  $updated = $wpdb->update(
    750                      $table_name,
    751                      array(
    752                          'article_content'   => $article_content,
    753                          'embedding_vector'  => $embedding_vector_serialized,
    754                          'source_url'        => $article_url,
    755                      ),
    756                      array('id' => $prompt_id),
    757                      array('%s', '%s', '%s'),
    758                      array('%d')
    759                  );
    760 
    761                  if ($updated !== false) {
    762                      wp_send_json_success();
    763                  } else {
    764                      wp_send_json_error(esc_html__('Database update failed.', 'mxchat'));
    765                  }
    766              } else {
    767                  wp_send_json_error(esc_html__('Embedding generation failed.', 'mxchat'));
    768              }
    769          } else {
    770              wp_send_json_error(esc_html__('Invalid data.', 'mxchat'));
    771          }
    772      }
     725   
     726    // Verify permissions
     727    if (!current_user_can('manage_options')) {
     728        wp_send_json_error(esc_html__('Permission denied.', 'mxchat'));
     729        return;
     730    }
     731   
     732    global $wpdb;
     733    $table_name = $wpdb->prefix . 'mxchat_system_prompt_content';
     734   
     735    // Validate and sanitize input data - FIXED LINE BELOW
     736    $prompt_id = isset($_POST['id']) ? absint($_POST['id']) : 0;
     737    $article_content = isset($_POST['article_content']) ? sanitize_textarea_field(wp_unslash($_POST['article_content'])) : '';
     738    $article_url = isset($_POST['article_url']) ? esc_url_raw($_POST['article_url']) : '';
     739   
     740    if ($prompt_id > 0 && !empty($article_content)) {
     741        // Re-generate the embedding vector for the updated content
     742        $embedding_vector = $this->mxchat_generate_embedding($article_content);
     743        if (is_array($embedding_vector)) {
     744            // Serialize the embedding vector before storing it
     745            $embedding_vector_serialized = serialize($embedding_vector);
     746            // Update the prompt in the database
     747            $updated = $wpdb->update(
     748                $table_name,
     749                array(
     750                    'article_content'   => $article_content,
     751                    'embedding_vector'  => $embedding_vector_serialized,
     752                    'source_url'        => $article_url,
     753                ),
     754                array('id' => $prompt_id),
     755                array('%s', '%s', '%s'),
     756                array('%d')
     757            );
     758            if ($updated !== false) {
     759                wp_send_json_success();
     760            } else {
     761                wp_send_json_error(esc_html__('Database update failed.', 'mxchat'));
     762            }
     763        } else {
     764            wp_send_json_error(esc_html__('Embedding generation failed.', 'mxchat'));
     765        }
     766    } else {
     767        wp_send_json_error(esc_html__('Invalid data.', 'mxchat'));
     768    }
     769}
    773770
    774771
  • mxchat-basic/trunk/css/admin-style.css

    r3341601 r3343848  
    52235223        border-left: 4px solid #72aee6;
    52245224    }
     5225   
     5226   
     5227    /* Hide email-dependent fields by default */
     5228tr:has(#email_blocker_header_content),
     5229tr:has(#email_blocker_button_text),
     5230tr:has(#enable_name_field),
     5231tr:has(#name_field_placeholder) {
     5232    display: none;
     5233}
     5234
     5235/* Show them when email block is enabled */
     5236body.email-block-enabled tr:has(#email_blocker_header_content),
     5237body.email-block-enabled tr:has(#email_blocker_button_text),
     5238body.email-block-enabled tr:has(#enable_name_field),
     5239body.email-block-enabled tr:has(#name_field_placeholder) {
     5240    display: table-row;
     5241}
     5242
     5243/* Style for email-dependent fields */
     5244.email-dependent-field {
     5245    background-color: #f8f9fa;
     5246    border-left: 4px solid #0073aa;
     5247    padding-left: 15px;
     5248    margin-left: 10px;
     5249}
     5250
     5251.email-dependent-field td,
     5252.email-dependent-field th {
     5253    background-color: #f8f9fa;
     5254}
  • mxchat-basic/trunk/css/chat-style.css

    r3323559 r3343848  
    5959}
    6060
    61 .email-blocker input[type="email"] {
     61.email-blocker input[type="email"],
     62.email-blocker .mxchat-name-input {
    6263    width: 100%;
    6364    padding: 12px;
     
    7172}
    7273
    73 .email-blocker input[type="email"]:focus {
     74.email-blocker input[type="email"]:focus,
     75.email-blocker .mxchat-name-input:focus {
    7476    border-color: #0073aa;
    7577    box-shadow: 0 0 8px rgba(0, 115, 170, 0.3);
  • mxchat-basic/trunk/includes/class-mxchat-addons.php

    r3341601 r3343848  
    161161     */
    162162    public function enqueue_styles() {
    163         $plugin_version = '2.3.7';
     163        $plugin_version = '2.3.8';
    164164
    165165        wp_enqueue_style(
  • mxchat-basic/trunk/includes/class-mxchat-admin.php

    r3341601 r3343848  
    4545
    4646        add_action('admin_notices', array($this, 'display_admin_notices'));
    47        
     47
    4848    add_action('wp_ajax_mxchat_test_streaming_actual', [$this, 'mxchat_handle_test_streaming_actual']);
    4949    add_action('wp_ajax_mxchat_test_streaming', [$this, 'mxchat_handle_test_streaming']); // Keep existing as fallback
    50    
     50
    5151
    5252    }
     
    9696        'email_blocker_header_content' => __("<h2>Welcome to Our Chat!</h2>\n<p>Let's get started. Enter your email to begin chatting with us.</p>", 'mxchat'),
    9797        'email_blocker_button_text' => esc_html__('Start Chat', 'mxchat'),
     98        'enable_name_field' => 'off', // NEW
     99        'name_field_placeholder' => esc_html__('Enter your name', 'mxchat'), // NEW
    98100        'top_bar_title' => esc_html__('MxChat', 'mxchat'),
    99101        'intro_message' => __('Hello! How can I assist you today?', 'mxchat'),
     
    237239public function mxchat_handle_test_streaming_actual() {
    238240    check_ajax_referer('mxchat_test_streaming_nonce', 'nonce');
    239    
     241
    240242    // Check if headers have already been sent
    241243    if (headers_sent()) {
     
    243245        return;
    244246    }
    245    
     247
    246248    // Check for required functions
    247249    if (!function_exists('curl_init')) {
     
    249251        return;
    250252    }
    251    
     253
    252254    // Get user's selected model and API key
    253255    $options = get_option('mxchat_options', []);
    254256    $selected_model = $options['model'] ?? 'gpt-4o';
    255    
     257
    256258    // Get the provider from the model
    257259    $model_parts = explode('-', $selected_model);
    258260    $provider = strtolower($model_parts[0]);
    259    
     261
    260262    // Get the appropriate API key
    261263    $api_key = '';
     
    283285            break;
    284286    }
    285    
     287
    286288    if (empty($api_key)) {
    287289        wp_send_json_error(['message' => "API key not configured for {$provider} provider"]);
    288290        return;
    289291    }
    290    
     292
    291293    // Test streaming with the selected model and provider
    292294    try {
     
    305307    header('Cache-Control: no-cache');
    306308    header('X-Accel-Buffering: no'); // Disable nginx buffering
    307    
     309
    308310    // Prepare test message
    309311    $test_message = "Please respond with exactly: 'Streaming test successful!' - send this as a short response for testing.";
    310    
     312
    311313    // Configure API request based on provider
    312314    $url = '';
    313315    $headers = [];
    314316    $body = [];
    315    
     317
    316318    switch ($provider) {
    317319        case 'gpt':
     
    330332            ];
    331333            break;
    332            
     334
    333335        case 'claude':
    334336            $url = 'https://api.anthropic.com/v1/messages';
     
    346348            ];
    347349            break;
    348            
     350
    349351        case 'grok':
    350352            $url = 'https://api.x.ai/v1/chat/completions';
     
    361363            ];
    362364            break;
    363            
     365
    364366        case 'deepseek':
    365367            $url = 'https://api.deepseek.com/v1/chat/completions';
     
    376378            ];
    377379            break;
    378            
     380
    379381        default:
    380382            echo "data: " . json_encode(['error' => 'Unsupported provider for streaming test: ' . $provider]) . "\n\n";
     
    382384            return;
    383385    }
    384    
     386
    385387    // Initialize cURL
    386388    $ch = curl_init();
     
    395397        return $this->process_streaming_test_data($data, $provider);
    396398    });
    397    
     399
    398400    // Send initial test message
    399401    echo "data: " . json_encode(['content' => '[Starting streaming test...]']) . "\n\n";
    400402    flush();
    401    
     403
    402404    $result = curl_exec($ch);
    403405    $http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    404406    $curl_error = curl_error($ch);
    405407    curl_close($ch);
    406    
     408
    407409    if ($curl_error) {
    408410        echo "data: " . json_encode(['error' => 'cURL Error: ' . $curl_error]) . "\n\n";
     
    410412        return;
    411413    }
    412    
     414
    413415    if ($http_code !== 200) {
    414416        echo "data: " . json_encode(['error' => 'API returned HTTP ' . $http_code]) . "\n\n";
     
    416418        return;
    417419    }
    418    
     420
    419421    // Send completion signal
    420422    echo "data: [DONE]\n\n";
     
    427429private function process_streaming_test_data($data, $provider) {
    428430    static $chunk_count = 0;
    429    
     431
    430432    $lines = explode("\n", $data);
    431    
     433
    432434    foreach ($lines as $line) {
    433435        if (trim($line) === '') {
    434436            continue;
    435437        }
    436        
     438
    437439        // Handle different provider formats
    438440        if ($provider === 'claude') {
     
    441443                $json_str = substr($line, 6);
    442444                $json = json_decode($json_str, true);
    443                
     445
    444446                if (isset($json['type']) && $json['type'] === 'content_block_delta') {
    445447                    if (isset($json['delta']['text'])) {
     
    457459            if (strpos($line, 'data: ') === 0) {
    458460                $json_str = substr($line, 6);
    459                
     461
    460462                if ($json_str === '[DONE]') {
    461463                    // Don't echo [DONE] here, let the main function handle it
    462464                    continue;
    463465                }
    464                
     466
    465467                $json = json_decode($json_str, true);
    466468                if (isset($json['choices'][0]['delta']['content'])) {
     
    475477        }
    476478    }
    477    
     479
    478480    return strlen($data);
    479481}
     
    484486public function mxchat_handle_test_streaming() {
    485487    check_ajax_referer('mxchat_test_streaming_nonce', 'nonce');
    486    
     488
    487489    // Use the actual streaming test instead
    488490    $this->mxchat_handle_test_streaming_actual();
     
    549551public function show_live_agent_disabled_banner() {
    550552    $show_disabled_notice = get_option('mxchat_show_live_agent_disabled_notice', false);
    551    
     553
    552554    if ($show_disabled_notice) {
    553555        ?>
     
    609611            </div>
    610612            <?php endif; ?>
    611            
    612             <?php 
    613             $this->show_live_agent_disabled_banner(); 
     613
     614            <?php
     615            $this->show_live_agent_disabled_banner();
    614616            ?>
    615617
     
    700702
    701703    <div class="tutorial-grid">
    702        
     704
    703705        <div class="tutorial-item">
    704706    <h3><?php echo esc_html__('AI Theme Generator Tutorial', 'mxchat'); ?></h3>
     
    712714</div>
    713715
    714        
     716
    715717        <div class="tutorial-item">
    716718            <h3><?php echo esc_html__('MxChat Forms Tutorial', 'mxchat'); ?></h3>
     
    860862    //error_log('dismiss_live_agent_notice called');
    861863    //error_log('POST data: ' . print_r($_POST, true));
    862    
     864
    863865    // Verify nonce
    864866    if (!wp_verify_nonce($_POST['nonce'], 'dismiss_live_agent_notice')) {
     
    866868        wp_die('Security check failed');
    867869    }
    868    
     870
    869871    // Remove the notice flag
    870872    $deleted = delete_option('mxchat_show_live_agent_disabled_notice');
    871873    //error_log('Option deleted: ' . ($deleted ? 'yes' : 'no'));
    872    
     874
    873875    wp_send_json_success();
    874876}
     
    11981200            session_id LIKE %s
    11991201            OR user_email LIKE %s
     1202            OR user_name LIKE %s
    12001203            OR user_identifier LIKE %s
    12011204            OR message LIKE %s
    12021205        )";
    1203         $search_params = array_fill(0, 4, '%' . $wpdb->esc_like($search) . '%');
     1206        $search_params = array_fill(0, 5, '%' . $wpdb->esc_like($search) . '%');
    12041207    }
    12051208
     
    12501253        $session_data = $originating_columns_exist
    12511254            ? $wpdb->get_row($wpdb->prepare(
    1252                 "SELECT user_email, user_identifier, originating_page_url, originating_page_title, timestamp
     1255                "SELECT user_email, user_name, user_identifier, originating_page_url, originating_page_title, timestamp
    12531256                 FROM {$table_name} WHERE session_id = %s ORDER BY timestamp ASC LIMIT 1",
    12541257                $session_id
    12551258            ))
    12561259            : $wpdb->get_row($wpdb->prepare(
    1257                 "SELECT user_email, user_identifier, timestamp FROM {$table_name}
     1260                "SELECT user_email, user_name, user_identifier, timestamp FROM {$table_name}
    12581261                 WHERE session_id = %s LIMIT 1",
    12591262                $session_id
     
    12861289
    12871290        $user_email = !empty($session_data->user_email) ? $session_data->user_email : '';
     1291        $user_name = !empty($session_data->user_name) ? $session_data->user_name : ''; // NEW
    12881292        $user_identifier = !empty($session_data->user_identifier) ? $session_data->user_identifier : 'Guest';
    1289         $user_display = !empty($user_email) ? $user_email : $user_identifier;
    1290 
     1293
     1294        // NEW: Build user display with name if available
     1295        if (!empty($user_email)) {
     1296            $user_display = $user_email;
     1297            if (!empty($user_name)) {
     1298                $user_display .= ' (' . $user_name . ')';
     1299            }
     1300        } else {
     1301            $user_display = $user_identifier;
     1302        }
    12911303        echo '<div class="mxchat-session">';
    12921304        echo '<div class="mxchat-session-header" data-session-id="' . esc_attr($session_id) . '">';
     
    14471459        );
    14481460    }
    1449    
     1461
    14501462    // First apply standard sanitization
    14511463    $message_content = wp_kses(
     
    14571469        ]
    14581470    );
    1459    
     1471
    14601472    // Process each clicked URL
    14611473    foreach ($clicked_urls as $clicked_url) {
     
    14691481            '/<a([^>]*href=["\']' . preg_quote(htmlentities($clicked_url), '/') . '["\'][^>]*)>/i',
    14701482        ];
    1471        
     1483
    14721484        foreach ($patterns as $pattern) {
    14731485            if (preg_match($pattern, $message_content)) {
     
    14771489                        $full_match = $matches[0];
    14781490                        $attributes = $matches[1];
    1479                        
     1491
    14801492                        // Check if it already has the class
    14811493                        if (strpos($full_match, 'mxchat-clicked-link') !== false) {
    14821494                            return $full_match;
    14831495                        }
    1484                        
     1496
    14851497                        // Check if class attribute exists
    14861498                        if (preg_match('/class=["\']([^"\']*)["\']/', $attributes, $class_matches)) {
     
    14951507                            $new_attributes = $attributes . ' class="mxchat-clicked-link"';
    14961508                        }
    1497                        
     1509
    14981510                        // Add title if not present
    14991511                        if (strpos($new_attributes, 'title=') === false) {
    15001512                            $new_attributes .= ' title="User clicked this link"';
    15011513                        }
    1502                        
     1514
    15031515                        return '<a' . $new_attributes . '>';
    15041516                    },
    15051517                    $message_content
    15061518                );
    1507                
     1519
    15081520                // If we found and replaced, break out of the patterns loop
    15091521                break;
     
    15111523        }
    15121524    }
    1513    
     1525
    15141526    return $message_content;
    15151527}
     
    15171529public function mxchat_create_prompts_page() {
    15181530    //error_log('=== DEBUG: mxchat_create_prompts_page started ===');
    1519    
     1531
    15201532    global $wpdb;
    15211533    $table_name = $wpdb->prefix . 'mxchat_system_prompt_content';
    1522    
     1534
    15231535    $knowledge_manager = MxChat_Knowledge_Manager::get_instance();
    15241536    $pinecone_manager = MxChat_Pinecone_Manager::get_instance();
     
    15461558    $pinecone_options = get_option('mxchat_pinecone_addon_options', array());
    15471559    //error_log('DEBUG: Pinecone options retrieved: ' . print_r($pinecone_options, true));
    1548    
     1560
    15491561    $use_pinecone = ($pinecone_options['mxchat_use_pinecone'] ?? '0') === '1';
    15501562    //error_log('DEBUG: use_pinecone decision: ' . ($use_pinecone ? 'TRUE' : 'FALSE'));
    1551    
     1563
    15521564    $pinecone_api_key = $pinecone_options['mxchat_pinecone_api_key'] ?? '';
    15531565    //error_log('DEBUG: Pinecone API key present: ' . (!empty($pinecone_api_key) ? 'YES' : 'NO'));
     
    15591571    $pinecone_manager = MxChat_Pinecone_Manager::get_instance();
    15601572    //error_log('DEBUG: About to call mxchat_fetch_pinecone_records');
    1561    
     1573
    15621574    $records = $pinecone_manager->mxchat_fetch_pinecone_records($pinecone_options, $search_query, $current_page, $per_page);
    15631575    $total_records = $records['total'] ?? 0;
     
    15671579
    15681580    $total_pages = ceil($total_records / $per_page);
    1569    
     1581
    15701582    //error_log('DEBUG: Pinecone - total_records: ' . $total_records);
    15711583    //error_log('DEBUG: Pinecone - prompts count: ' . count($prompts));
     
    15771589    // WORDPRESS DB DATA SOURCE (your existing logic)
    15781590    $data_source = 'wordpress';
    1579    
     1591
    15801592    // Initialize these variables for WordPress DB
    15811593    $total_in_database = 0;
     
    15931605    $count_query = "SELECT COUNT(*) FROM {$table_name} {$sql_search}";
    15941606    //error_log('DEBUG: WordPress count query: ' . $count_query);
    1595    
     1607
    15961608    $total_records = $wpdb->get_var($count_query);
    15971609    //error_log('DEBUG: WordPress total_records: ' . $total_records);
    1598    
     1610
    15991611    $total_pages = ceil($total_records / $per_page);
    16001612
     
    16061618    );
    16071619    //error_log('DEBUG: WordPress prompts query: ' . $prompts_query);
    1608    
     1620
    16091621    $prompts = $wpdb->get_results($prompts_query);
    16101622    //error_log('DEBUG: WordPress prompts count: ' . count($prompts));
     
    16491661
    16501662    //error_log('=== DEBUG: mxchat_create_prompts_page data preparation completed ===');
    1651    
     1663
    16521664    ?>
    16531665
     
    17761788               </div>
    17771789           </button>
    1778            
     1790
    17791791                      <!-- PDF Import Option -->
    17801792           <button type="button" class="mxchat-import-box" data-option="pdf" data-placeholder="<?php esc_attr_e('Enter PDF URL here', 'mxchat'); ?>" data-type="pdf">
     
    18461858           <div class="mxchat-status-header">
    18471859               <h4><?php esc_html_e('PDF Processing Status', 'mxchat'); ?></h4>
    1848                
     1860
    18491861                <!-- Processing controls -->
    18501862                <div class="mxchat-processing-controls">
     
    18561868                        </button>
    18571869                    </form>
    1858                    
    1859                     <button type="button" class="mxchat-manual-batch-btn" 
     1870
     1871                    <button type="button" class="mxchat-manual-batch-btn"
    18601872                            data-process-type="pdf"
    18611873                            data-url="<?php echo esc_attr(get_transient('mxchat_last_pdf_url')); ?>">
     
    18641876                </div>
    18651877           </div>
    1866            
     1878
    18671879           <div class="mxchat-progress-bar">
    18681880               <div class="mxchat-progress-fill" style="width: <?php echo esc_attr($pdf_status['percentage']); ?>%"></div>
    18691881           </div>
    1870            
     1882
    18711883           <div class="mxchat-status-details">
    18721884               <p><?php printf(
     
    18761888                   absint($pdf_status['percentage'])
    18771889               ); ?></p>
    1878                
     1890
    18791891               <?php if (!empty($pdf_status['failed_pages']) && $pdf_status['failed_pages'] > 0) : ?>
    18801892                   <p><strong><?php esc_html_e('Failed pages:', 'mxchat'); ?></strong> <?php echo esc_html($pdf_status['failed_pages']); ?></p>
    18811893               <?php endif; ?>
    1882                
     1894
    18831895               <p><strong><?php esc_html_e('Status:', 'mxchat'); ?></strong> <?php echo esc_html(ucfirst($pdf_status['status'])); ?></p>
    18841896               <p><strong><?php esc_html_e('Last update:', 'mxchat'); ?></strong> <?php echo esc_html($pdf_status['last_update']); ?></p>
     
    18921904           <div class="mxchat-status-header">
    18931905               <h4><?php esc_html_e('Sitemap Processing Status', 'mxchat'); ?></h4>
    1894                
     1906
    18951907                <!-- Processing controls -->
    18961908                <div class="mxchat-processing-controls">
     
    19021914                        </button>
    19031915                    </form>
    1904                    
    1905                     <button type="button" class="mxchat-manual-batch-btn" 
     1916
     1917                    <button type="button" class="mxchat-manual-batch-btn"
    19061918                            data-process-type="sitemap"
    19071919                            data-url="<?php echo esc_attr(get_transient('mxchat_last_sitemap_url')); ?>">
     
    19101922                </div>
    19111923           </div>
    1912            
     1924
    19131925           <div class="mxchat-progress-bar">
    19141926               <div class="mxchat-progress-fill" style="width: <?php echo esc_attr($sitemap_status['percentage']); ?>%"></div>
    19151927           </div>
    1916            
     1928
    19171929           <div class="mxchat-status-details">
    19181930               <p><?php printf(
     
    19221934                   absint($sitemap_status['percentage'])
    19231935               ); ?></p>
    1924                
     1936
    19251937               <?php if (!empty($sitemap_status['failed_urls']) && $sitemap_status['failed_urls'] > 0) : ?>
    19261938                   <p><strong><?php esc_html_e('Failed URLs:', 'mxchat'); ?></strong> <?php echo esc_html($sitemap_status['failed_urls']); ?></p>
    19271939               <?php endif; ?>
    1928                
     1940
    19291941               <p><strong><?php esc_html_e('Status:', 'mxchat'); ?></strong> <?php echo esc_html(ucfirst($sitemap_status['status'])); ?></p>
    19301942               <p><strong><?php esc_html_e('Last update:', 'mxchat'); ?></strong> <?php echo esc_html($sitemap_status['last_update']); ?></p>
    1931                
     1943
    19321944               <?php if (!empty($sitemap_status['error']) || !empty($sitemap_status['last_error'])) : ?>
    19331945                   <div class="mxchat-error-notice">
     
    19451957
    19461958   <!-- Single URL Submission Status -->
    1947    <?php 
     1959   <?php
    19481960   // Get single URL status
    19491961    $single_url_status = $this->knowledge_manager->mxchat_get_single_url_status();
    1950    $is_active_processing = 
    1951        ($sitemap_status && $sitemap_status['status'] === 'processing') || 
     1962   $is_active_processing =
     1963       ($sitemap_status && $sitemap_status['status'] === 'processing') ||
    19521964       ($pdf_status && $pdf_status['status'] === 'processing');
    19531965   ?>
     
    19651977               </div>
    19661978               <div class="mxchat-status-details">
    1967                    <p><strong><?php esc_html_e('URL:', 'mxchat'); ?></strong> 
     1979                   <p><strong><?php esc_html_e('URL:', 'mxchat'); ?></strong>
    19681980                       <a href="<?php echo esc_url($single_url_status['url']); ?>" target="_blank">
    19691981                           <?php echo esc_html(strlen($single_url_status['url']) > 60 ? substr($single_url_status['url'], 0, 57) . '...' : $single_url_status['url']); ?>
     
    19861998       <?php endif; ?>
    19871999   </div>
    1988    
     2000
    19892001   <!-- Completed Status Cards - Handles completed PDF/Sitemap processing -->
    19902002   <?php
     
    20492061        </div>
    20502062    </div>
    2051    
     2063
    20522064    <!-- Recent Entries Info Banner -->
    20532065<?php if ($showing_recent_only && $total_in_database > 1000): ?>
     
    21252137                                    <textarea class="content-edit" style="display:none;"
    21262138                                              <?php if (preg_match('/[\x{0590}-\x{05FF}]/u', $prompt->article_content)) echo 'dir="rtl" lang="he"'; ?>>
    2127                                         <?php echo esc_textarea($prompt->article_content); ?>
     2139                                        <?php echo htmlspecialchars($prompt->article_content, ENT_QUOTES, 'UTF-8'); ?>
    21282140                                    </textarea>
    21292141                                <?php endif; ?>
     
    21422154                                <?php if ($data_source === 'wordpress') : ?>
    21432155                                    <input type="text" class="url-edit" style="display:none;"
    2144                                            value="<?php echo esc_attr($prompt->source_url); ?>" />
     2156                                       value="<?php echo htmlspecialchars($prompt->source_url, ENT_QUOTES, 'UTF-8'); ?>" />
    21452157                                <?php endif; ?>
    21462158                            </td>
     
    21772189                                <?php if ($data_source === 'pinecone') : ?>
    21782190                                    <!-- AJAX Delete for Pinecone -->
    2179                                     <button type="button" 
     2191                                    <button type="button"
    21802192                                            class="mxchat-button-icon delete-button-ajax"
    21812193                                            data-vector-id="<?php echo esc_attr($prompt->id); ?>"
     
    25742586<?php
    25752587}
     2588
     2589
    25762590public function mxchat_delete_chat_history() {
    25772591    if (!current_user_can('manage_options')) {
     
    26212635    wp_die();
    26222636}
    2623 
    26242637public function display_admin_notices() {
    26252638    // Check if we're on a MXChat admin page
     
    26672680    $license_error = get_option('mxchat_license_error', '');
    26682681    $current_domain = parse_url(home_url(), PHP_URL_HOST);
    2669    
    2670     // Your website URL - change this to your actual website
    2671     $license_management_url = 'https://mxchat.ai/my-account/license-management/';
    2672    
     2682
     2683    $license_management_url = 'https://mxchat.ai/my-account/orders/';
     2684
    26732685    // Check if this activation has been linked to a domain
    26742686    $is_domain_linked = $this->is_current_activation_linked($current_domain);
     
    26872699            </p>
    26882700        </div>
    2689        
     2701
    26902702        <?php if ($license_status === 'inactive' && !empty($license_error)): ?>
    26912703            <div class="error notice">
     
    26932705            </div>
    26942706        <?php endif; ?>
    2695        
     2707
    26962708        <!-- Domain Linking Notice for Existing Users -->
    26972709        <?php if ($license_status === 'active' && !$is_domain_linked): ?>
     
    27092721            </div>
    27102722        <?php endif; ?>
    2711        
     2723
    27122724        <!-- Activation Form -->
    27132725        <form id="mxchat-activation-form" class="mxchat-pro-form" style="<?php echo $license_status === 'active' ? 'display: none;' : ''; ?>">
     
    27272739                    </tr>
    27282740                </table>
    2729                
     2741
    27302742                <!-- Hidden field for domain -->
    27312743                <input type="hidden" id="mxchat_domain" name="domain" value="<?php echo esc_attr($current_domain); ?>" />
    2732                
     2744
    27332745                <?php if ($license_status !== 'active'): ?>
    27342746                    <div class="mxchat-pro-button-container">
     
    27392751            </div>
    27402752        </form>
    2741        
     2753
    27422754        <!-- License Status Display -->
    27432755        <div class="mxchat-pro-status">
     
    27472759                </span>
    27482760            </h3>
    2749            
     2761
    27502762            <?php if ($license_status === 'active'): ?>
    27512763                <div class="mxchat-license-details">
     
    27582770                    </p>
    27592771                    <p><strong><?php esc_html_e('Email:', 'mxchat'); ?></strong> <?php echo esc_html(get_option('mxchat_pro_email')); ?></p>
    2760                     <p><strong><?php esc_html_e('License Key:', 'mxchat'); ?></strong> 
     2772                    <p><strong><?php esc_html_e('License Key:', 'mxchat'); ?></strong>
    27612773                        <code style="background: #f1f1f1; padding: 2px 6px; border-radius: 3px;">
    27622774                            <?php echo esc_html(get_option('mxchat_activation_key')); ?>
     
    27652777                    <p>
    27662778                        <small>
    2767                             <?php esc_html_e('Manage all your licenses and domains on', 'mxchat'); ?> 
     2779                            <?php esc_html_e('Manage all your licenses and domains on', 'mxchat'); ?>
    27682780                            <a href="<?php echo esc_url($license_management_url); ?>" target="_blank">
    27692781                                <?php esc_html_e('your account dashboard', 'mxchat'); ?>
     
    27712783                        </small>
    27722784                    </p>
    2773                    
     2785
    27742786                    <!-- Deactivation Section -->
    27752787                    <div class="mxchat-deactivation-section" style="margin-top: 20px; padding: 15px; background: #fff3cd; border-left: 4px solid #ffc107; border-radius: 4px;">
     
    27882800            <?php endif; ?>
    27892801        </div>
    2790        
     2802
    27912803        <!-- Hidden fields for JavaScript -->
    27922804        <input type="hidden" id="mxchat-ajax-url" value="<?php echo admin_url('admin-ajax.php'); ?>" />
     
    28042816    $license_key = get_option('mxchat_activation_key');
    28052817    $email = get_option('mxchat_pro_email');
    2806    
     2818
    28072819    if (empty($license_key) || empty($email)) {
    28082820        return false;
    28092821    }
    2810    
     2822
    28112823    // Check with YOUR website's API
    28122824    $response = wp_remote_post('https://mxchat.ai/mxchat-api/check-domain', array(
     
    28192831        'sslverify' => false
    28202832    ));
    2821    
     2833
    28222834    if (is_wp_error($response)) {
    28232835        return false;
    28242836    }
    2825    
     2837
    28262838    $body = json_decode(wp_remote_retrieve_body($response), true);
    28272839    return isset($body['success']) && $body['success'] && isset($body['data']['linked']) && $body['data']['linked'];
     
    37523764        'mxchat_chatbot_section'
    37533765    );
    3754    
     3766
    37553767    add_settings_field(
    37563768        'contextual_awareness_toggle',
     
    38323844            )
    38333845        );
    3834        
     3846
    38353847    add_settings_field(
    38363848        'enable_streaming_toggle',
     
    38533865        'mxchat_chatbot_section'
    38543866    );
    3855    
     3867
    38563868    add_settings_field(
    38573869        'embedding_model',
     
    39073919        esc_html__('Require Email Chat Button Text', 'mxchat'),
    39083920        [$this, 'email_blocker_button_text_callback'],
     3921        'mxchat-chatbot',
     3922        'mxchat_chatbot_section'
     3923    );
     3924
     3925    add_settings_field(
     3926        'enable_name_field',
     3927        esc_html__('Require Name Field', 'mxchat'),
     3928        array($this, 'enable_name_field_callback'),
     3929        'mxchat-chatbot',
     3930        'mxchat_chatbot_section'
     3931    );
     3932
     3933    add_settings_field(
     3934        'name_field_placeholder',
     3935        esc_html__('Name Field Placeholder', 'mxchat'),
     3936        array($this, 'name_field_placeholder_callback'),
    39093937        'mxchat-chatbot',
    39103938        'mxchat_chatbot_section'
     
    42044232        'mxchat_live_agent_section'
    42054233    );
    4206    
     4234
    42074235    add_settings_field(
    42084236        'live_agent_user_ids',
     
    45024530                esc_textarea($custom_message) .
    45034531              '</textarea>';
    4504         echo '<p class="description">' . 
    4505              esc_html__('Example: Rate limit reached! [Visit our pricing page](https://example.com/pricing) to upgrade.', 'mxchat') . 
     4532        echo '<p class="description">' .
     4533             esc_html__('Example: Rate limit reached! [Visit our pricing page](https://example.com/pricing) to upgrade.', 'mxchat') .
    45064534             '</p>';
    45074535        echo '</div>'; // End message
     
    48534881    $enabled = isset($this->options['enable_streaming_toggle']) ? $this->options['enable_streaming_toggle'] : 'on';
    48544882    $checked = ($enabled === 'on') ? 'checked' : '';
    4855    
     4883
    48564884    echo '<label class="toggle-switch">';
    48574885    echo sprintf(
     
    48614889    echo '<span class="slider"></span>';
    48624890    echo '</label>';
    4863     echo '<p class="description">' . 
    4864         esc_html__('Enable real-time streaming responses for supported models (OpenAI, Claude, and Grok). When disabled, responses will load all at once.', 'mxchat') . 
     4891    echo '<p class="description">' .
     4892        esc_html__('Enable real-time streaming responses for supported models (OpenAI, Claude, and Grok). When disabled, responses will load all at once.', 'mxchat') .
    48654893    '</p>';
    4866    
     4894
    48674895    // Test button with better styling
    48684896    echo '<div style="margin-top: 15px;">';
     
    49815009    echo '<p class="description">';
    49825010    echo esc_html__('Enter the text you want on the submit button, e.g. "Start Chat".', 'mxchat');
     5011    echo '</p>';
     5012}
     5013
     5014
     5015//Enable name field callback
     5016public function enable_name_field_callback() {
     5017    // Load full plugin options array
     5018    $all_options = get_option('mxchat_options', []);
     5019    // Get the value, default to 'off'
     5020    $enable_name_field = isset($all_options['enable_name_field']) ? $all_options['enable_name_field'] : 'off';
     5021    // Check if it's 'on'
     5022    $checked = ($enable_name_field === 'on') ? 'checked' : '';
     5023    echo '<label class="toggle-switch">';
     5024    echo sprintf(
     5025        '<input type="checkbox" id="enable_name_field" name="enable_name_field" value="on" %s />',
     5026        esc_attr($checked)
     5027    );
     5028    echo '<span class="slider"></span>';
     5029    echo '</label>';
     5030    echo '<p class="description">' . esc_html__('Enable this to also require users to enter their name along with their email before chatting.', 'mxchat') . '</p>';
     5031}
     5032//Name field placeholder callback
     5033public function name_field_placeholder_callback() {
     5034    $all_options = get_option('mxchat_options', []);
     5035    $placeholder = isset($all_options['name_field_placeholder'])
     5036        ? $all_options['name_field_placeholder']
     5037        : esc_html__('Enter your name', 'mxchat');
     5038
     5039    echo '<input type="text" id="name_field_placeholder" name="name_field_placeholder" value="' . esc_attr($placeholder) . '" style="width: 300px;" />';
     5040    echo '<p class="description">';
     5041    echo esc_html__('Placeholder text for the name field.', 'mxchat');
    49835042    echo '</p>';
    49845043}
     
    59075966    $fresh_options = get_option('mxchat_options');
    59085967    $status = isset($fresh_options['live_agent_status']) ? $fresh_options['live_agent_status'] : 'off';
    5909    
     5968
    59105969    echo '<label class="toggle-switch">';
    59115970    echo sprintf(
     
    59766035
    59776036public function mxchat_live_agent_user_ids_callback() {
    5978     $user_ids = isset($this->options['live_agent_user_ids']) 
    5979         ? esc_textarea($this->options['live_agent_user_ids']) 
     6037    $user_ids = isset($this->options['live_agent_user_ids'])
     6038        ? esc_textarea($this->options['live_agent_user_ids'])
    59806039        : '';
    5981    
     6040
    59826041    printf(
    59836042        '<textarea id="live_agent_user_ids" name="live_agent_user_ids" rows="4" class="large-text">%s</textarea>',
     
    60226081public function mxchat_enqueue_admin_assets() {
    60236082    // Get plugin version (define this in your main plugin file)
    6024     $version = defined('MXCHAT_VERSION') ? MXCHAT_VERSION : '2.3.7';
    6025    
     6083    $version = defined('MXCHAT_VERSION') ? MXCHAT_VERSION : '2.3.8';
     6084
    60266085    // Use file modification time for development (remove in production)
    60276086    if (defined('WP_DEBUG') && WP_DEBUG) {
    60286087        $version = filemtime(plugin_dir_path(__FILE__) . '../mxchat-basic.php');
    60296088    }
    6030    
     6089
    60316090    $current_page = isset($_GET['page']) ? $_GET['page'] : '';
    60326091    $plugin_url = plugin_dir_url(__FILE__) . '../';
    6033    
     6092
    60346093    // Only load on MxChat pages
    60356094    if (strpos($current_page, 'mxchat') === false) {
    60366095        return;
    60376096    }
    6038    
     6097
    60396098    // Always load these on all MxChat pages
    60406099    $this->enqueue_core_admin_assets($plugin_url, $version);
     
    60466105    wp_enqueue_style('mxchat-admin-css', $plugin_url . 'css/admin-style.css', array(), $version);
    60476106    wp_enqueue_style('mxchat-knowledge-css', $plugin_url . 'css/knowledge-style.css', array(), $version);
    6048    
     6107
    60496108    // Core admin scripts
    60506109    wp_enqueue_script('mxchat-admin-js', $plugin_url . 'js/mxchat-admin.js', array('jquery'), $version, true);
     
    60596118            wp_enqueue_script('mxchat-knowledge-processing', $plugin_url . 'js/knowledge-processing.js', array('jquery'), $version, true);
    60606119            break;
    6061            
     6120
    60626121        case 'mxchat-transcripts':
    60636122            wp_enqueue_style('mxchat-chat-transcripts-css', $plugin_url . 'css/chat-transcripts.css', array(), $version);
    60646123            wp_enqueue_script('mxchat-transcripts-js', $plugin_url . 'js/mxchat_transcripts.js', array('jquery'), $version, true);
    60656124            break;
    6066            
     6125
    60676126        case 'mxchat-actions':
    60686127            wp_enqueue_style('mxchat-intent-css', $plugin_url . 'css/intent-style.css', array(), $version);
    60696128            break;
    6070            
     6129
    60716130        case 'mxchat-activation':
    60726131            wp_enqueue_script('mxchat-activation-js', $plugin_url . 'js/activation-script.js', array('jquery'), $version, true);
     
    61076166        'ajaxurl' => admin_url('admin-ajax.php') // For jQuery fallback
    61086167    );
    6109    
     6168
    61106169    // Localize main admin script with base data
    61116170    wp_localize_script('mxchat-admin-js', 'mxchatAdmin', $base_data);
    6112    
     6171
    61136172    // Page-specific localizations
    61146173    $this->localize_page_specific_scripts($current_page);
     
    61226181                'nonce' => wp_create_nonce('mxchat_status_nonce')
    61236182            ));
    6124            
     6183
    61256184            // Content selector localization
    61266185            wp_localize_script('mxchat-content-selector-js', 'mxchatSelector', array(
     
    61356194                )
    61366195            ));
    6137            
     6196
    61386197            // NEW: Knowledge processing script localization using mxchatAdmin
    61396198            wp_localize_script('mxchat-knowledge-processing', 'mxchatAdmin', array(
     
    61466205            ));
    61476206            break;
    6148            
     6207
    61496208        case 'mxchat-activation':
    61506209            wp_localize_script('mxchat-activation-js', 'mxchatAdmin', array(
     
    61536212            ));
    61546213            break;
    6155            
     6214
    61566215        case 'mxchat-settings':
    61576216        default:
     
    61946253            break;
    61956254    }
    6196    
     6255
    61976256    // Additional localization that was in the original code
    61986257    wp_localize_script('mxchat-admin-js', 'mxchatPromptsAdmin', array(
     
    62216280        $new_input['claude_api_key'] = sanitize_text_field($input['claude_api_key']);
    62226281    }
    6223    
     6282
    62246283    if (isset($input['enable_streaming_toggle'])) {
    62256284        $new_input['enable_streaming_toggle'] = ($input['enable_streaming_toggle'] === 'on') ? 'on' : 'off';
     
    62286287        $new_input['enable_streaming_toggle'] = 'off';
    62296288    }
    6230    
     6289
    62316290
    62326291    if (isset($input['deepseek_api_key'])) {
     
    62716330        $new_input['append_to_body'] = $input['append_to_body'] === 'on' ? 'on' : 'off';
    62726331    }
    6273    
     6332
    62746333    if (isset($input['contextual_awareness_toggle'])) {
    62756334    $new_input['contextual_awareness_toggle'] = $input['contextual_awareness_toggle'] === 'on' ? 'on' : 'off';
     
    62956354        $new_input['email_blocker_button_text'] = sanitize_text_field($input['email_blocker_button_text']);
    62966355    }
    6297 
     6356    // NEW: Sanitize name field toggle
     6357    if (isset($input['enable_name_field'])) {
     6358        $new_input['enable_name_field'] = ($input['enable_name_field'] === 'on') ? 'on' : 'off';
     6359    } else {
     6360        $new_input['enable_name_field'] = 'off';
     6361    }
     6362    // NEW: Sanitize name field placeholder
     6363    if (isset($input['name_field_placeholder'])) {
     6364        $new_input['name_field_placeholder'] = sanitize_text_field($input['name_field_placeholder']);
     6365    }
    62986366    if (isset($input['intro_message'])) {
    62996367        $new_input['intro_message'] = wp_kses_post($input['intro_message']);  // Use wp_kses_post instead
     
    64636531        $new_input['top_bar_bg_color'] = sanitize_hex_color($input['top_bar_bg_color']);
    64646532    }
    6465    
     6533
    64666534    if (isset($input['quick_questions_toggle_color'])) {
    64676535        $new_input['quick_questions_toggle_color'] = sanitize_hex_color($input['quick_questions_toggle_color']);
     
    66116679        $new_input['live_agent_bot_token'] = sanitize_text_field($input['live_agent_bot_token']);
    66126680    }
    6613    
     6681
    66146682    if (isset($input['live_agent_user_ids'])) {
    66156683    $new_input['live_agent_user_ids'] = sanitize_textarea_field($input['live_agent_user_ids']);
     
    67156783        delete_option('mxchat_pinecone_processed_cache');
    67166784        delete_option('mxchat_processed_content_cache');
    6717        
     6785
    67186786        // CLEAR THE PINECONE RECORDS CACHE (NEW LINE)
    67196787        delete_transient('mxchat_pinecone_recent_1k_cache');
    6720        
     6788
    67216789    } else {
    67226790        //error_log('[MXCHAT-DELETE] Pinecone not enabled - deleting from WordPress database');
     
    69457013         exit;
    69467014     }
    6947      
    6948      
     7015
     7016
    69497017/**
    69507018 * Checks user permissions for managing options
     
    69557023    }
    69567024    check_admin_referer('mxchat_add_intent_nonce');
    6957    
     7025
    69587026    global $wpdb;
    69597027    $table_name = $wpdb->prefix . 'mxchat_intents';
    6960    
     7028
    69617029    // Sanitize and get form data
    69627030    $intent_label = isset($_POST['intent_label']) ? sanitize_text_field($_POST['intent_label']) : '';
    69637031    $phrases_input = isset($_POST['phrases']) ? sanitize_textarea_field($_POST['phrases']) : '';
    69647032    $callback_function = isset($_POST['callback_function']) ? sanitize_text_field($_POST['callback_function']) : '';
    6965    
     7033
    69667034    // Get similarity threshold from form (convert percentage to decimal)
    69677035    $similarity_threshold = isset($_POST['similarity_threshold']) ? floatval($_POST['similarity_threshold']) / 100 : 0.85;
    6968    
     7036
    69697037    // Validate required fields
    69707038    if (empty($intent_label) || empty($callback_function) || empty($phrases_input)) {
     
    69727040        return;
    69737041    }
    6974    
     7042
    69757043    // Validate callback function
    69767044    $available_callbacks = $this->mxchat_get_available_callbacks();
     
    69797047        return;
    69807048    }
    6981    
     7049
    69827050    // Check Pro requirements
    69837051    $is_pro_only = $available_callbacks[$callback_function]['pro_only'];
     
    69867054        return;
    69877055    }
    6988    
     7056
    69897057    // Process phrases
    69907058    $phrases_array = array_map('sanitize_text_field', array_filter(array_map('trim', explode(',', $phrases_input))));
     
    69937061        return;
    69947062    }
    6995    
     7063
    69967064    // Generate embeddings with improved error handling
    69977065    $vectors = [];
     
    70057073        }
    70067074    }
    7007    
     7075
    70087076    // Check for embedding failures
    70097077    if (!empty($failed_phrases)) {
     
    70167084        return;
    70177085    }
    7018    
     7086
    70197087    if (empty($vectors)) {
    70207088        $this->handle_embedding_error(__('No valid embeddings generated. Please check your phrases.', 'mxchat'));
    70217089        return;
    70227090    }
    7023    
     7091
    70247092    // Create combined vector and insert into database
    70257093    $combined_vector = $this->mxchat_average_vectors($vectors);
    70267094    $serialized_vector = maybe_serialize($combined_vector);
    7027    
     7095
    70287096    $result = $wpdb->insert($table_name, [
    70297097        'intent_label'         => $intent_label,
     
    70337101        'similarity_threshold' => $similarity_threshold,  // Now uses the actual form value
    70347102    ]);
    7035    
     7103
    70367104    if ($result === false) {
    70377105        $this->handle_embedding_error(__('Database error: ', 'mxchat') . $wpdb->last_error);
    70387106        return;
    70397107    }
    7040    
     7108
    70417109    // Set success message and redirect
    70427110    set_transient('mxchat_admin_notice_success', __('New intent added successfully!', 'mxchat'), 60);
     
    70447112    exit;
    70457113}
    7046      
     7114
    70477115        /**
    70487116     * Averages multiple vectors into a single vector
     
    70667134         return $sum_vector;
    70677135     }
    7068  
    7069      
    7070      
    7071      
     7136
     7137
     7138
     7139
    70727140         /**
    70737141     * Generates embeddings from input text for MXChat
  • mxchat-basic/trunk/includes/class-mxchat-integrator.php

    r3341601 r3343848  
    372372    //error_log("[DEBUG] mxchat_save_chat_message -> Checking wp_options for email_option_key: {$email_option_key}, found: {$saved_email}");
    373373   
    374     // If found, update DB user_email
    375     if ($saved_email) {
    376         $update_res = $wpdb->update(
    377             $table_name,
    378             ['user_email' => $saved_email],
    379             ['session_id' => $session_id],
    380             ['%s'],
    381             ['%s']
    382         );
    383         //error_log("[DEBUG] mxchat_save_chat_message -> Attempted DB user_email update for session_id {$session_id}. update_res: {$update_res}");
     374    // NEW: Check for a saved name in wp_options
     375    $name_option_key = "mxchat_name_{$session_id}";
     376    $saved_name = get_option($name_option_key);
     377    //error_log("[DEBUG] mxchat_save_chat_message -> Checking wp_options for name_option_key: {$name_option_key}, found: {$saved_name}");
     378   
     379    // If found, update DB user_email and user_name
     380    if ($saved_email || $saved_name) {
     381        $update_data = [];
     382        if ($saved_email) {
     383            $update_data['user_email'] = $saved_email;
     384        }
     385        if ($saved_name) {
     386            $update_data['user_name'] = $saved_name;
     387        }
     388       
     389        if (!empty($update_data)) {
     390            $update_res = $wpdb->update(
     391                $table_name,
     392                $update_data,
     393                ['session_id' => $session_id],
     394                array_fill(0, count($update_data), '%s'),
     395                ['%s']
     396            );
     397            //error_log("[DEBUG] mxchat_save_chat_message -> Attempted DB user_email/user_name update for session_id {$session_id}. update_res: {$update_res}");
     398        }
    384399    }
    385400   
     
    402417        'user_identifier'=> $user_identifier,
    403418        'user_email'     => $saved_email ?: $user_email,
     419        'user_name'      => $saved_name ?: '', // NEW: Add name to insert data
    404420        'session_id'     => $session_id,
    405421        'role'           => $role,
     
    483499    return $message_id;
    484500}
    485 
    486501private function send_new_chat_notification($session_id, $user_info = array()) {
    487502    $options = get_option('mxchat_transcripts_options');
     
    530545public function mxchat_handle_save_email_and_response() {
    531546    //error_log('[DEBUG] ---------- mxchat_handle_save_email_and_response START ----------');
     547    error_log('DEBUG: POST data: ' . print_r($_POST, true));
    532548
    533549    // Validate nonce
     
    540556    $session_id = isset($_POST['session_id']) ? sanitize_text_field($_POST['session_id']) : '';
    541557    $email      = isset($_POST['email']) ? sanitize_email($_POST['email']) : '';
    542 
    543     //error_log("[DEBUG] handle_save_email_and_response -> session_id: {$session_id}, email: {$email}");
     558    $name       = isset($_POST['name']) ? sanitize_text_field($_POST['name']) : ''; // NEW
     559
     560    //error_log("[DEBUG] handle_save_email_and_response -> session_id: {$session_id}, email: {$email}, name: {$name}");
    544561
    545562    if (empty($session_id) || empty($email)) {
     
    549566    }
    550567
    551     // 1) Always store in wp_options
    552     $option_key = "mxchat_email_{$session_id}";
    553     update_option($option_key, $email);
    554     //error_log("[DEBUG] handle_save_email_and_response -> updated option: {$option_key} => {$email}");
     568    // NEW: Validate name if provided (check if name field is enabled and name is required)
     569    $options = get_option('mxchat_options', []);
     570    $name_field_enabled = isset($options['enable_name_field']) &&
     571        ($options['enable_name_field'] === '1' || $options['enable_name_field'] === 'on');
     572   
     573    if ($name_field_enabled && (empty($name) || strlen(trim($name)) < 2 || strlen(trim($name)) > 100)) {
     574        //error_log("[ERROR] Invalid name: {$name} (enabled: {$name_field_enabled})");
     575        wp_send_json_error(['message' => esc_html__('Name must be between 2 and 100 characters.', 'mxchat')]);
     576        wp_die();
     577    }
     578
     579    // 1) Always store email in wp_options
     580    $email_option_key = "mxchat_email_{$session_id}";
     581    update_option($email_option_key, $email);
     582    //error_log("[DEBUG] handle_save_email_and_response -> updated option: {$email_option_key} => {$email}");
     583
     584    // NEW: Store name in wp_options if provided
     585    if (!empty($name)) {
     586        $name_option_key = "mxchat_name_{$session_id}";
     587        update_option($name_option_key, $name);
     588        //error_log("[DEBUG] handle_save_email_and_response -> updated option: {$name_option_key} => {$name}");
     589    }
    555590
    556591    // 2) (Optional) Also store in DB if a row already exists
     
    565600
    566601    if ($session_count) {
    567         // Update user_email if row(s) exist
    568         $update_sql = $wpdb->prepare(
    569             "UPDATE {$table_name} SET user_email = %s WHERE session_id = %s",
    570             $email,
    571             $session_id
    572         );
     602        // NEW: Update both user_email and user_name if row(s) exist
     603        if (!empty($name)) {
     604            $update_sql = $wpdb->prepare(
     605                "UPDATE {$table_name} SET user_email = %s, user_name = %s WHERE session_id = %s",
     606                $email,
     607                $name,
     608                $session_id
     609            );
     610        } else {
     611            $update_sql = $wpdb->prepare(
     612                "UPDATE {$table_name} SET user_email = %s WHERE session_id = %s",
     613                $email,
     614                $session_id
     615            );
     616        }
    573617        $wpdb->query($update_sql);
    574618        //error_log("[DEBUG] handle_save_email_and_response -> DB updated: {$update_sql}");
    575619    } else {
    576         //error_log("[INFO] handle_save_email_and_response -> No DB entry for {$session_id}, so email is only in wp_options.");
    577     }
    578 
    579     // Provide success response
     620        //error_log("[INFO] handle_save_email_and_response -> No DB entry for {$session_id}, so email/name is only in wp_options.");
     621    }
     622
     623    // Provide success response (same as original)
    580624    $bot_message = __('Thanks for providing your email! You can continue chatting now.', 'mxchat');
    581625    //error_log("[DEBUG] handle_save_email_and_response -> success, returning bot_message: {$bot_message}");
     
    602646        $current_user = wp_get_current_user();
    603647        //error_log("[DEBUG] User is logged in as {$current_user->user_email}");
    604         wp_send_json_success(['logged_in' => true, 'email' => $current_user->user_email]);
    605     }
    606 
    607     $option_key = "mxchat_email_{$session_id}";
    608     $stored_email = get_option($option_key, '');
    609 
    610     //error_log("[DEBUG] mxchat_check_email_provided -> Checking option: {$option_key}, found: {$stored_email}");
    611 
    612     if (!empty($stored_email)) {
    613         //error_log("[DEBUG] mxchat_check_email_provided -> Email found, returning success");
    614         wp_send_json_success(['email' => $stored_email]);
     648       
     649        // NEW: Get user's display name for logged in users
     650        $user_name = !empty($current_user->display_name) ? $current_user->display_name :
     651                    (!empty($current_user->first_name) ? $current_user->first_name : '');
     652       
     653        $response_data = ['logged_in' => true, 'email' => $current_user->user_email];
     654        if (!empty($user_name)) {
     655            $response_data['name'] = $user_name;
     656        }
     657       
     658        wp_send_json_success($response_data);
     659    }
     660
     661    // NEW: Check if name field is required
     662    $options = get_option('mxchat_options', []);
     663    $name_field_enabled = isset($options['enable_name_field']) &&
     664        ($options['enable_name_field'] === '1' || $options['enable_name_field'] === 'on');
     665
     666    $email_option_key = "mxchat_email_{$session_id}";
     667    $stored_email = get_option($email_option_key, '');
     668   
     669    // NEW: Check for stored name
     670    $name_option_key = "mxchat_name_{$session_id}";
     671    $stored_name = get_option($name_option_key, '');
     672
     673    //error_log("[DEBUG] mxchat_check_email_provided -> Checking email option: {$email_option_key}, found: {$stored_email}");
     674    //error_log("[DEBUG] mxchat_check_email_provided -> Checking name option: {$name_option_key}, found: {$stored_name}, required: " . ($name_field_enabled ? 'yes' : 'no'));
     675
     676    // NEW: Check if we have email and name (if name is required)
     677    $has_required_info = !empty($stored_email);
     678   
     679    if ($name_field_enabled) {
     680        $has_required_info = $has_required_info && !empty($stored_name);
     681    }
     682
     683    if ($has_required_info) {
     684        //error_log("[DEBUG] mxchat_check_email_provided -> Required info found, returning success");
     685       
     686        $response_data = ['email' => $stored_email];
     687        if (!empty($stored_name)) {
     688            $response_data['name'] = $stored_name;
     689        }
     690       
     691        wp_send_json_success($response_data);
    615692    } else {
    616         //error_log("[DEBUG] mxchat_check_email_provided -> No email found, returning error");
     693        //error_log("[DEBUG] mxchat_check_email_provided -> Required info missing, returning error");
    617694        wp_send_json_error(['message' => esc_html__('No email found', 'mxchat')]);
    618695    }
     
    25582635    if (empty($channel_id)) {
    25592636        // Create new channel with session ID as name
    2560         $channel_name = 'chat-' . strtolower(preg_replace('/[^a-zA-Z0-9]/', '', $session_id));
     2637            $channel_name = $this->generate_channel_name($session_id);
    25612638       
    25622639        //error_log("Attempting to create channel: $channel_name");
     
    26952772    ]);
    26962773    wp_die();
     2774}
     2775private function generate_channel_name($session_id) {
     2776    $email = null;
     2777   
     2778    // 1. First priority: Check if user is logged in and get their email
     2779    if (is_user_logged_in()) {
     2780        $current_user = wp_get_current_user();
     2781        if (!empty($current_user->user_email)) {
     2782            $email = $current_user->user_email;
     2783            error_log("[DEBUG] Using logged-in user email for channel: {$email}");
     2784        }
     2785    }
     2786   
     2787    // 2. Second priority: Check for saved email from "require email to chat" option
     2788    if (empty($email)) {
     2789        $email_option_key = "mxchat_email_{$session_id}";
     2790        $saved_email = get_option($email_option_key);
     2791        if (!empty($saved_email)) {
     2792            $email = $saved_email;
     2793            error_log("[DEBUG] Using saved email from session for channel: {$email}");
     2794        }
     2795    }
     2796   
     2797    // 3. Third priority: Check existing chat transcript for email
     2798    if (empty($email)) {
     2799        global $wpdb;
     2800        $table_name = $wpdb->prefix . 'mxchat_chat_transcripts';
     2801        $existing_email = $wpdb->get_var($wpdb->prepare(
     2802            "SELECT user_email FROM $table_name WHERE session_id = %s AND user_email IS NOT NULL AND user_email != '' LIMIT 1",
     2803            $session_id
     2804        ));
     2805        if (!empty($existing_email)) {
     2806            $email = $existing_email;
     2807            error_log("[DEBUG] Using email from chat transcript for channel: {$email}");
     2808        }
     2809    }
     2810   
     2811    // 4. Generate channel name based on what we found
     2812    if (!empty($email)) {
     2813        // Convert email to valid Slack channel name
     2814        // Slack channel names must be lowercase, no spaces, and only certain special chars
     2815        $channel_name = 'chat-' . strtolower(str_replace(['@', '.', '+', '_'], ['-at-', '-', '-plus-', '-'], $email));
     2816        // Remove any remaining invalid characters
     2817        $channel_name = preg_replace('/[^a-z0-9\-]/', '', $channel_name);
     2818        // Ensure it doesn't end with a hyphen
     2819        $channel_name = rtrim($channel_name, '-');
     2820        // Slack channel names have a 21 character limit, so truncate if needed
     2821        if (strlen($channel_name) > 21) {
     2822            $channel_name = substr($channel_name, 0, 21);
     2823            $channel_name = rtrim($channel_name, '-'); // Remove trailing hyphen if truncation created one
     2824        }
     2825    } else {
     2826        // Fallback to session ID if no email found
     2827        $channel_name = 'chat-' . strtolower(preg_replace('/[^a-zA-Z0-9]/', '', $session_id));
     2828        error_log("[DEBUG] No email found, using session ID for channel: {$channel_name}");
     2829    }
     2830   
     2831    error_log("[DEBUG] Generated channel name: {$channel_name}");
     2832    return $channel_name;
    26972833}
    26982834public function mxchat_send_user_message_to_agent($message, $user_id, $session_id) {
     
    55245660public function mxchat_enqueue_scripts_styles() {
    55255661    // Define version numbers for the styles and scripts
    5526     $chat_style_version = '2.3.7';
    5527     $chat_script_version = '2.3.7';
     5662    $chat_style_version = '2.3.8';
     5663    $chat_script_version = '2.3.8';
    55285664    // Enqueue the script
    55295665    wp_enqueue_script(
     
    55755711        'toolbar_icon_color' => $this->options['toolbar_icon_color'] ?? '#212121',
    55765712        'use_pinecone' => $prompts_options['mxchat_use_pinecone'] ?? '0',
     5713        'email_collection_enabled' => $enable_email_block,
     5714        'initial_email_state' => $email_state ?? null,
     5715        'skip_email_check' => true,
    55775716        'pinecone_enabled' => isset($prompts_options['mxchat_use_pinecone']) && $prompts_options['mxchat_use_pinecone'] === '1'
    55785717    );
  • mxchat-basic/trunk/includes/class-mxchat-public.php

    r3335923 r3343848  
    9696    }
    9797
    98     public function render_chatbot_shortcode($atts) {
    99         $attributes = shortcode_atts(array(
    100             'floating' => 'yes',
    101             'has_consent' => 'yes'  // Add default
    102         ), $atts);
    103 
    104         $is_floating = $attributes['floating'] === 'yes';
    105        
    106         // Check for Complianz consent if the toggle is enabled
    107         $initial_visibility = 'hidden';
    108         $additional_class = '';
    109        
    110         if (isset($this->options['complianz_toggle']) && $this->options['complianz_toggle'] === 'on') {
    111             // If Complianz is enabled, add no-consent class by default
    112             $additional_class = ' no-consent';
    113         }
    114         $visibility_class = $initial_visibility . $additional_class;
    115        
    116         $theme_options = get_option('mxchat_theme_options', array());
    117         $custom_send_image = isset($theme_options['custom_send_button_image']) ? esc_url($theme_options['custom_send_button_image']) : '';
    118         $send_width = isset($theme_options['send_button_width']) ? intval($theme_options['send_button_width']) : 24;
    119         $send_height = isset($theme_options['send_button_height']) ? intval($theme_options['send_button_height']) : 24;
    120         $send_rotation = isset($theme_options['send_button_rotation']) ? intval($theme_options['send_button_rotation']) : 0;
    121        
    122         // Use null coalescing operator (??) for fallbacks instead of having duplicate defaults
    123         $bg_color = $this->options['chatbot_background_color'] ?? '#fff';
    124         $user_message_bg_color = $this->options['user_message_bg_color'] ?? '#fff';
    125         $user_message_font_color = $this->options['user_message_font_color'] ?? '#212121';
    126         $bot_message_bg_color = $this->options['bot_message_bg_color'] ?? '#212121';
    127         $bot_message_font_color = $this->options['bot_message_font_color'] ?? '#fff';
    128         $top_bar_bg_color = $this->options['top_bar_bg_color'] ?? '#212121';
    129         $send_button_font_color = $this->options['send_button_font_color'] ?? '#212121';
    130         $intro_message = $this->options['intro_message'] ?? esc_html__('Hello! How can I assist you today?', 'mxchat');
    131         $top_bar_title = $this->options['top_bar_title'] ?? esc_html__('MxChat: Basic', 'mxchat');
    132         $chatbot_background_color = $this->options['chatbot_background_color'] ?? '#212121';
    133         $icon_color = $this->options['icon_color'] ?? '#fff';
    134         $chat_input_font_color = $this->options['chat_input_font_color'] ?? '#212121';
    135         $close_button_color = $this->options['close_button_color'] ?? '#fff';
    136         $chatbot_bg_color = $this->options['chatbot_bg_color'] ?? '#fff';
    137         $pre_chat_message = isset($this->options['pre_chat_message']) ? sanitize_text_field(trim($this->options['pre_chat_message'])) : '';
    138         $user_id = sanitize_key($this->mxchat_get_user_identifier());
    139         $transient_key = 'mxchat_pre_chat_message_dismissed_' . $user_id;
    140         $input_copy = isset($this->options['input_copy']) ? esc_attr($this->options['input_copy']) : esc_attr__('How can I assist?', 'mxchat');
    141         $rate_limit_message = isset($this->options['rate_limit_message']) ? esc_attr($this->options['rate_limit_message']) : esc_attr__('Rate limit exceeded. Please try again later.', 'mxchat');
    142         $mode_indicator_bg_color = $this->options['mode_indicator_bg_color'] ?? '#212121';
    143         $mode_indicator_font_color = $this->options['mode_indicator_font_color'] ?? '#fff';
    144         $quick_questions_toggle_color = $this->options['quick_questions_toggle_color'] ?? '#212121';
    145 
    146         $privacy_toggle = isset($this->options['privacy_toggle']) && $this->options['privacy_toggle'] === 'on';
    147         $privacy_text = isset($this->options['privacy_text']) ? wp_kses_post($this->options['privacy_text']) : wp_kses_post(__('By chatting, you agree to our <a href="https://example.com/privacy-policy" target="_blank">privacy policy</a>.', 'mxchat'));
    148 
    149         $popular_question_1 = isset($this->options['popular_question_1']) ? esc_html($this->options['popular_question_1']) : '';
    150         $popular_question_2 = isset($this->options['popular_question_2']) ? esc_html($this->options['popular_question_2']) : '';
    151         $popular_question_3 = isset($this->options['popular_question_3']) ? esc_html($this->options['popular_question_3']) : '';
    152         $additional_questions = isset($this->options['additional_popular_questions']) ? $this->options['additional_popular_questions'] : [];
    153         $custom_icon = isset($this->options['custom_icon']) ? esc_url($this->options['custom_icon']) : '';
    154         $title_icon = isset($this->options['title_icon']) ? esc_url($this->options['title_icon']) : '';
    155         $ai_agent_text = isset($this->options['ai_agent_text']) ? esc_html($this->options['ai_agent_text']) : esc_html__('AI Agent', 'mxchat');
    156 
    157         $live_agent_message_bg_color = $this->options['live_agent_message_bg_color'] ?? '#212121';
    158         $live_agent_message_font_color = $this->options['live_agent_message_font_color'] ?? '#fff';
    159         $enable_email_block = isset($this->options['enable_email_block']) &&
    160             ($this->options['enable_email_block'] === '1' || $this->options['enable_email_block'] === 'on');
    161 
    162         ob_start();
     98public function render_chatbot_shortcode($atts) {
     99    $attributes = shortcode_atts(array(
     100        'floating' => 'yes',
     101        'has_consent' => 'yes'
     102    ), $atts);
     103
     104    $is_floating = $attributes['floating'] === 'yes';
     105   
     106    // Check for Complianz consent if the toggle is enabled
     107    $initial_visibility = 'hidden';
     108    $additional_class = '';
     109   
     110    if (isset($this->options['complianz_toggle']) && $this->options['complianz_toggle'] === 'on') {
     111        $additional_class = ' no-consent';
     112    }
     113    $visibility_class = $initial_visibility . $additional_class;
     114   
     115    $theme_options = get_option('mxchat_theme_options', array());
     116    $custom_send_image = isset($theme_options['custom_send_button_image']) ? esc_url($theme_options['custom_send_button_image']) : '';
     117    $send_width = isset($theme_options['send_button_width']) ? intval($theme_options['send_button_width']) : 24;
     118    $send_height = isset($theme_options['send_button_height']) ? intval($theme_options['send_button_height']) : 24;
     119    $send_rotation = isset($theme_options['send_button_rotation']) ? intval($theme_options['send_button_rotation']) : 0;
     120   
     121    // Existing variables...
     122    $bg_color = $this->options['chatbot_background_color'] ?? '#fff';
     123    $user_message_bg_color = $this->options['user_message_bg_color'] ?? '#fff';
     124    $user_message_font_color = $this->options['user_message_font_color'] ?? '#212121';
     125    $bot_message_bg_color = $this->options['bot_message_bg_color'] ?? '#212121';
     126    $bot_message_font_color = $this->options['bot_message_font_color'] ?? '#fff';
     127    $top_bar_bg_color = $this->options['top_bar_bg_color'] ?? '#212121';
     128    $send_button_font_color = $this->options['send_button_font_color'] ?? '#212121';
     129    $intro_message = $this->options['intro_message'] ?? esc_html__('Hello! How can I assist you today?', 'mxchat');
     130    $top_bar_title = $this->options['top_bar_title'] ?? esc_html__('MxChat: Basic', 'mxchat');
     131    $chatbot_background_color = $this->options['chatbot_background_color'] ?? '#212121';
     132    $icon_color = $this->options['icon_color'] ?? '#fff';
     133    $chat_input_font_color = $this->options['chat_input_font_color'] ?? '#212121';
     134    $close_button_color = $this->options['close_button_color'] ?? '#fff';
     135    $chatbot_bg_color = $this->options['chatbot_bg_color'] ?? '#fff';
     136    $pre_chat_message = isset($this->options['pre_chat_message']) ? sanitize_text_field(trim($this->options['pre_chat_message'])) : '';
     137    $user_id = sanitize_key($this->mxchat_get_user_identifier());
     138    $email_state = $this->determine_email_collection_state();
     139    $show_email_form = $email_state['show_email_form'];
     140    $user_email = $email_state['user_email'] ?? '';
     141    $user_name = $email_state['user_name'] ?? '';
     142    $transient_key = 'mxchat_pre_chat_message_dismissed_' . $user_id;
     143    $input_copy = isset($this->options['input_copy']) ? esc_attr($this->options['input_copy']) : esc_attr__('How can I assist?', 'mxchat');
     144    $rate_limit_message = isset($this->options['rate_limit_message']) ? esc_attr($this->options['rate_limit_message']) : esc_attr__('Rate limit exceeded. Please try again later.', 'mxchat');
     145    $mode_indicator_bg_color = $this->options['mode_indicator_bg_color'] ?? '#212121';
     146    $mode_indicator_font_color = $this->options['mode_indicator_font_color'] ?? '#fff';
     147    $quick_questions_toggle_color = $this->options['quick_questions_toggle_color'] ?? '#212121';
     148
     149    $privacy_toggle = isset($this->options['privacy_toggle']) && $this->options['privacy_toggle'] === 'on';
     150    $privacy_text = isset($this->options['privacy_text']) ? wp_kses_post($this->options['privacy_text']) : wp_kses_post(__('By chatting, you agree to our <a href="https://example.com/privacy-policy" target="_blank">privacy policy</a>.', 'mxchat'));
     151
     152    $popular_question_1 = isset($this->options['popular_question_1']) ? esc_html($this->options['popular_question_1']) : '';
     153    $popular_question_2 = isset($this->options['popular_question_2']) ? esc_html($this->options['popular_question_2']) : '';
     154    $popular_question_3 = isset($this->options['popular_question_3']) ? esc_html($this->options['popular_question_3']) : '';
     155    $additional_questions = isset($this->options['additional_popular_questions']) ? $this->options['additional_popular_questions'] : [];
     156    $custom_icon = isset($this->options['custom_icon']) ? esc_url($this->options['custom_icon']) : '';
     157    $title_icon = isset($this->options['title_icon']) ? esc_url($this->options['title_icon']) : '';
     158    $ai_agent_text = isset($this->options['ai_agent_text']) ? esc_html($this->options['ai_agent_text']) : esc_html__('AI Agent', 'mxchat');
     159
     160    $live_agent_message_bg_color = $this->options['live_agent_message_bg_color'] ?? '#212121';
     161    $live_agent_message_font_color = $this->options['live_agent_message_font_color'] ?? '#fff';
     162    $enable_email_block = isset($this->options['enable_email_block']) &&
     163        ($this->options['enable_email_block'] === '1' || $this->options['enable_email_block'] === 'on');
     164
     165    // NEW: Add name field variables
     166    $enable_name_field = isset($this->options['enable_name_field']) &&
     167        ($this->options['enable_name_field'] === '1' || $this->options['enable_name_field'] === 'on');
     168    $name_field_placeholder = isset($this->options['name_field_placeholder']) ?
     169        esc_attr($this->options['name_field_placeholder']) :
     170        esc_attr__('Enter your name', 'mxchat');
     171
     172    ob_start();
    163173
    164174        // Check if floating attribute is set to 'yes' and wrap accordingly
     
    190200        echo '  <div id="mxchat-chatbot" style="background-color: ' . esc_attr($chatbot_bg_color) . ';">';
    191201           
    192         if ($enable_email_block) {
    193             echo '<div id="email-blocker" class="email-blocker">';
    194             echo '    <div class="email-blocker-header">';
    195        
    196             // Safely echo the user-provided HTML
    197             // (We rely on wp_kses_post() from the sanitize step to ensure it's safe)
    198             $header_html = isset($this->options['email_blocker_header_content'])
    199                 ? $this->options['email_blocker_header_content']
    200                 : '';
    201             echo wp_kses_post($header_html);
    202        
    203             echo '    </div>';
    204             echo '    <form id="email-collection-form">';
    205             echo '        <label for="user-email" class="sr-only">' . esc_html__('Email Address', 'mxchat') . '</label>';
    206             echo '        <input type="email" id="user-email" name="user_email" required placeholder="' . esc_attr__('Enter your email address', 'mxchat') . '" />';
    207             echo '<button type="submit" id="email-submit-button">';
    208                 // If not set, fallback to default. Typically, $this->options includes defaults merged in.
    209                 $button_text = isset($this->options['email_blocker_button_text'])
    210                     ? $this->options['email_blocker_button_text']
    211                     : esc_html__('Start Chat', 'mxchat'); // fallback just in case
    212                 echo esc_html($button_text);
    213             echo '</button>';
    214             echo '    </form>';
    215             echo '</div>';
    216         }
    217    
    218         echo '      <div id="chat-container" style="' . ($enable_email_block ? 'display: none;' : '') . '">';
     202if ($enable_email_block) {
     203    echo '<div id="email-blocker" class="email-blocker" style="' . ($show_email_form ? '' : 'display: none;') . '">';
     204    echo '    <div class="email-blocker-header">';
     205
     206    $header_html = isset($this->options['email_blocker_header_content'])
     207        ? $this->options['email_blocker_header_content']
     208        : '';
     209    echo wp_kses_post($header_html);
     210
     211    echo '    </div>';
     212    echo '    <form id="email-collection-form">';
     213   
     214    // NEW: Add name field if enabled
     215    if ($enable_name_field) {
     216        echo '        <label for="user-name" class="sr-only mxchat-name-label">' . esc_html__('Name', 'mxchat') . '</label>';
     217        echo '        <input type="text" id="user-name" name="user_name" class="mxchat-name-input" required placeholder="' . $name_field_placeholder . '" />';
     218    }
     219   
     220    echo '        <label for="user-email" class="sr-only">' . esc_html__('Email Address', 'mxchat') . '</label>';
     221    echo '        <input type="email" id="user-email" name="user_email" required placeholder="' . esc_attr__('Enter your email address', 'mxchat') . '" />';
     222    echo '<button type="submit" id="email-submit-button">';
     223        $button_text = isset($this->options['email_blocker_button_text'])
     224            ? $this->options['email_blocker_button_text']
     225            : esc_html__('Start Chat', 'mxchat');
     226        echo esc_html($button_text);
     227    echo '</button>';
     228    echo '    </form>';
     229    echo '</div>';
     230}
     231   
     232        echo '      <div id="chat-container" style="' . ($enable_email_block && $show_email_form ? 'display: none;' : '') . '">';
    219233        echo '          <div id="chat-box">';
    220234        echo '              <div class="bot-message" style="background: ' . esc_attr($bot_message_bg_color) . ';">';
     
    383397        return ob_get_clean();
    384398    }
     399   
     400   
     401   
     402    private function determine_email_collection_state() {
     403    // Get session ID
     404    $session_id = 'mxchat_chat_' . wp_generate_uuid4(); // You'll need to use your actual session generation logic
     405   
     406    // Check if user is logged in first
     407    if (is_user_logged_in()) {
     408        $current_user = wp_get_current_user();
     409        return [
     410            'show_email_form' => false,
     411            'user_email' => $current_user->user_email,
     412            'user_name' => $current_user->display_name ?: $current_user->first_name ?: ''
     413        ];
     414    }
     415   
     416    // Check stored email for session
     417    $stored_email = get_option("mxchat_email_{$session_id}", '');
     418    $stored_name = get_option("mxchat_name_{$session_id}", '');
     419   
     420    // Check if name is required
     421    $name_field_enabled = isset($this->options['enable_name_field']) &&
     422        ($this->options['enable_name_field'] === '1' || $this->options['enable_name_field'] === 'on');
     423   
     424    $has_required_info = !empty($stored_email);
     425    if ($name_field_enabled) {
     426        $has_required_info = $has_required_info && !empty($stored_name);
     427    }
     428   
     429    return [
     430        'show_email_form' => !$has_required_info,
     431        'user_email' => $stored_email,
     432        'user_name' => $stored_name
     433    ];
     434}
     435   
     436   
     437   
     438   
     439   
     440   
    385441}
    386442?>
  • mxchat-basic/trunk/js/chat-script.js

    r3340699 r3343848  
    20372037
    20382038// ====================================
    2039 // IMPROVED EMAIL COLLECTION SETUP
     2039// EMAIL COLLECTION SETUP
    20402040// ====================================
    2041 
    20422041// Email collection form setup and handlers
    20432042const emailForm = document.getElementById('email-collection-form');
     
    20462045
    20472046if (emailForm && emailBlocker && chatbotWrapper) {
     2047   
     2048    // NEW: Check if server already provided the email state
     2049    if (mxchatChat.skip_email_check && mxchatChat.initial_email_state) {
     2050        console.log('Using server-provided email state:', mxchatChat.initial_email_state);
     2051       
     2052        // Use server-provided state instead of making AJAX call
     2053        const emailState = mxchatChat.initial_email_state;
     2054        if (emailState.show_email_form) {
     2055            showEmailForm();
     2056        } else {
     2057            showChatContainer();
     2058        }
     2059       
     2060        // Continue to set up form handlers but skip the AJAX check
     2061        setupFormHandlers();
     2062       
     2063    } else {
     2064        // FALLBACK: Use existing AJAX approach if server state not available
     2065        console.log('Server state not available, using AJAX fallback');
     2066        setupFormHandlers();
     2067        // Initialize email check with delay to prevent race conditions
     2068        setTimeout(checkSessionAndEmail, 100);
     2069    }
     2070
    20482071    // Add loading state management
    20492072    let isSubmitting = false;
     
    21182141    }
    21192142
     2143    // Enhanced name validation
     2144    function isValidName(name) {
     2145        return name && name.trim().length >= 2 && name.trim().length <= 100;
     2146    }
     2147
    21202148    // Show loading state with spinner
    21212149    function setSubmissionState(loading) {
    21222150        const submitButton = document.getElementById('email-submit-button');
    21232151        const emailInput = document.getElementById('user-email');
     2152        const nameInput = document.getElementById('user-name');
    21242153       
    21252154        if (loading) {
     
    21272156            submitButton.disabled = true;
    21282157            emailInput.disabled = true;
     2158            if (nameInput) nameInput.disabled = true;
    21292159           
    21302160            // Store original content and add spinner
     
    21502180            submitButton.disabled = false;
    21512181            emailInput.disabled = false;
     2182            if (nameInput) nameInput.disabled = false;
    21522183           
    21532184            // Restore original content
     
    21592190            submitButton.style.opacity = '1';
    21602191        }
    2161     }
    2162 
    2163     // Add CSS for spinner animation if not already present
    2164     if (!document.getElementById('email-spinner-styles')) {
    2165         const style = document.createElement('style');
    2166         style.id = 'email-spinner-styles';
    2167         style.textContent = `
    2168             @keyframes spin {
    2169                 from { transform: rotate(0deg); }
    2170                 to { transform: rotate(360deg); }
    2171             }
    2172             .email-spinner {
    2173                 display: inline-block;
    2174                 vertical-align: middle;
    2175             }
    2176         `;
    2177         document.head.appendChild(style);
    2178     }
    2179 
    2180     // Handle email form submission with improved error handling
    2181     emailForm.addEventListener('submit', function (event) {
    2182         event.preventDefault();
    2183        
    2184         // Prevent double submission
    2185         if (isSubmitting) {
    2186             return;
    2187         }
    2188 
    2189         const userEmail = document.getElementById('user-email').value.trim();
    2190         const sessionId = getChatSession();
    2191 
    2192         // Validate email before submission
    2193         if (!userEmail) {
    2194             showEmailError('Please enter your email address.');
    2195             return;
    2196         }
    2197 
    2198         if (!isValidEmail(userEmail)) {
    2199             showEmailError('Please enter a valid email address.');
    2200             return;
    2201         }
    2202 
    2203         // Clear any existing errors
    2204         clearEmailError();
    2205         setSubmissionState(true);
    2206 
    2207         // Add timeout for submission
    2208         const controller = new AbortController();
    2209         const timeoutId = setTimeout(() => {
    2210             controller.abort();
    2211             setSubmissionState(false);
    2212             showEmailError('Request timed out. Please try again.');
    2213         }, 15000); // 15 second timeout
    2214 
    2215         fetch(mxchatChat.ajax_url, {
    2216             method: 'POST',
    2217             headers: {
    2218                 'Content-Type': 'application/x-www-form-urlencoded',
    2219             },
    2220             body: new URLSearchParams({
    2221                 action: 'mxchat_handle_save_email_and_response',
    2222                 email: userEmail,
    2223                 session_id: sessionId,
    2224                 nonce: mxchatChat.nonce,
    2225             }),
    2226             signal: controller.signal
    2227         })
    2228         .then((response) => {
    2229             clearTimeout(timeoutId);
    2230             if (!response.ok) {
    2231                 throw new Error(`HTTP error! status: ${response.status}`);
    2232             }
    2233             return response.json();
    2234         })
    2235         .then((data) => {
    2236             setSubmissionState(false);
    2237            
    2238             if (data.success) {
    2239                 // Show chat immediately
    2240                 showChatContainer();
    2241 
    2242                 // Handle bot response if provided
    2243                 if (data.message && typeof appendMessage === 'function') {
    2244                     setTimeout(() => {
    2245                         appendMessage('bot', data.message);
    2246                         if (typeof scrollToBottom === 'function') {
    2247                             scrollToBottom();
    2248                         }
    2249                     }, 100);
    2250                 }
    2251             } else {
    2252                 showEmailError(data.message || 'Failed to save email. Please try again.');
    2253             }
    2254         })
    2255         .catch((error) => {
    2256             clearTimeout(timeoutId);
    2257             setSubmissionState(false);
    2258            
    2259             if (error.name === 'AbortError') {
    2260                 showEmailError('Request timed out. Please try again.');
    2261             } else {
    2262                 console.error('Email submission error:', error);
    2263                 showEmailError('An error occurred. Please try again.');
    2264             }
    2265         });
    2266     });
    2267 
    2268     // Real-time email validation
    2269     const emailInput = document.getElementById('user-email');
    2270     if (emailInput) {
    2271         let validationTimeout;
    2272        
    2273         emailInput.addEventListener('input', function() {
    2274             // Clear previous validation timeout
    2275             if (validationTimeout) {
    2276                 clearTimeout(validationTimeout);
    2277             }
    2278            
    2279             // Debounce validation
    2280             validationTimeout = setTimeout(() => {
    2281                 const email = this.value.trim();
    2282                 clearEmailError();
    2283                
    2284                 if (email && !isValidEmail(email)) {
    2285                     showEmailError('Please enter a valid email address.');
    2286                 }
    2287             }, 500);
    2288         });
    2289 
    2290         // Handle Enter key
    2291         emailInput.addEventListener('keypress', function(e) {
    2292             if (e.key === 'Enter' && !isSubmitting) {
    2293                 emailForm.dispatchEvent(new Event('submit'));
    2294             }
    2295         });
    22962192    }
    22972193
     
    23342230        emailForm.appendChild(errorDiv);
    23352231       
    2336         // Add shake animation to input
     2232        // Add shake animation to inputs
     2233        const emailInput = document.getElementById('user-email');
     2234        const nameInput = document.getElementById('user-name');
     2235       
    23372236        if (emailInput) {
    23382237            emailInput.classList.add('email-input-shake');
     
    23412240            }, 500);
    23422241        }
     2242       
     2243        if (nameInput) {
     2244            nameInput.classList.add('email-input-shake');
     2245            setTimeout(() => {
     2246                nameInput.classList.remove('email-input-shake');
     2247            }, 500);
     2248        }
    23432249    }
    23442250
     
    23482254    }
    23492255
    2350     // Initialize email check with delay to prevent race conditions
    2351     setTimeout(checkSessionAndEmail, 100);
    2352    
    2353 } else if (mxchatChat.email_collection_enabled) {
     2256    // NEW: Separate function to set up all form handlers
     2257    function setupFormHandlers() {
     2258        // Add CSS for spinner animation if not already present
     2259        if (!document.getElementById('email-spinner-styles')) {
     2260            const style = document.createElement('style');
     2261            style.id = 'email-spinner-styles';
     2262            style.textContent = `
     2263                @keyframes spin {
     2264                    from { transform: rotate(0deg); }
     2265                    to { transform: rotate(360deg); }
     2266                }
     2267                .email-spinner {
     2268                    display: inline-block;
     2269                    vertical-align: middle;
     2270                }
     2271            `;
     2272            document.head.appendChild(style);
     2273        }
     2274
     2275        // Handle email form submission with improved error handling
     2276        emailForm.addEventListener('submit', function (event) {
     2277            event.preventDefault();
     2278           
     2279            // Prevent double submission
     2280            if (isSubmitting) {
     2281                return;
     2282            }
     2283
     2284            const userEmail = document.getElementById('user-email').value.trim();
     2285            const nameInput = document.getElementById('user-name');
     2286            const userName = nameInput ? nameInput.value.trim() : '';
     2287            const sessionId = getChatSession();
     2288
     2289            // Validate email before submission
     2290            if (!userEmail) {
     2291                showEmailError('Please enter your email address.');
     2292                return;
     2293            }
     2294
     2295            if (!isValidEmail(userEmail)) {
     2296                showEmailError('Please enter a valid email address.');
     2297                return;
     2298            }
     2299
     2300            // Validate name if field exists
     2301            if (nameInput && !isValidName(userName)) {
     2302                showEmailError('Please enter a valid name (2-100 characters).');
     2303                return;
     2304            }
     2305
     2306            // Clear any existing errors
     2307            clearEmailError();
     2308            setSubmissionState(true);
     2309
     2310            // Add timeout for submission
     2311            const controller = new AbortController();
     2312            const timeoutId = setTimeout(() => {
     2313                controller.abort();
     2314                setSubmissionState(false);
     2315                showEmailError('Request timed out. Please try again.');
     2316            }, 15000); // 15 second timeout
     2317
     2318            // Prepare form data with optional name
     2319            const formData = new URLSearchParams({
     2320                action: 'mxchat_handle_save_email_and_response',
     2321                email: userEmail,
     2322                session_id: sessionId,
     2323                nonce: mxchatChat.nonce,
     2324            });
     2325
     2326            // Add name to form data if provided
     2327            if (userName) {
     2328                formData.append('name', userName);
     2329            }
     2330
     2331            fetch(mxchatChat.ajax_url, {
     2332                method: 'POST',
     2333                headers: {
     2334                    'Content-Type': 'application/x-www-form-urlencoded',
     2335                },
     2336                body: formData,
     2337                signal: controller.signal
     2338            })
     2339            .then((response) => {
     2340                clearTimeout(timeoutId);
     2341                if (!response.ok) {
     2342                    throw new Error(`HTTP error! status: ${response.status}`);
     2343                }
     2344                return response.json();
     2345            })
     2346            .then((data) => {
     2347                setSubmissionState(false);
     2348               
     2349                if (data.success) {
     2350                    // Show chat immediately
     2351                    showChatContainer();
     2352
     2353                    // Handle bot response if provided
     2354                    if (data.message && typeof appendMessage === 'function') {
     2355                        setTimeout(() => {
     2356                            appendMessage('bot', data.message);
     2357                            if (typeof scrollToBottom === 'function') {
     2358                                scrollToBottom();
     2359                            }
     2360                        }, 100);
     2361                    }
     2362                } else {
     2363                    showEmailError(data.message || 'Failed to save email. Please try again.');
     2364                }
     2365            })
     2366            .catch((error) => {
     2367                clearTimeout(timeoutId);
     2368                setSubmissionState(false);
     2369               
     2370                if (error.name === 'AbortError') {
     2371                    showEmailError('Request timed out. Please try again.');
     2372                } else {
     2373                    console.error('Email submission error:', error);
     2374                    showEmailError('An error occurred. Please try again.');
     2375                }
     2376            });
     2377        });
     2378
     2379        // Real-time email validation
     2380        const emailInput = document.getElementById('user-email');
     2381        if (emailInput) {
     2382            let validationTimeout;
     2383           
     2384            emailInput.addEventListener('input', function() {
     2385                // Clear previous validation timeout
     2386                if (validationTimeout) {
     2387                    clearTimeout(validationTimeout);
     2388                }
     2389               
     2390                // Debounce validation
     2391                validationTimeout = setTimeout(() => {
     2392                    const email = this.value.trim();
     2393                    clearEmailError();
     2394                   
     2395                    if (email && !isValidEmail(email)) {
     2396                        showEmailError('Please enter a valid email address.');
     2397                    }
     2398                }, 500);
     2399            });
     2400
     2401            // Handle Enter key
     2402            emailInput.addEventListener('keypress', function(e) {
     2403                if (e.key === 'Enter' && !isSubmitting) {
     2404                    emailForm.dispatchEvent(new Event('submit'));
     2405                }
     2406            });
     2407        }
     2408
     2409        // Real-time name validation
     2410        const nameInput = document.getElementById('user-name');
     2411        if (nameInput) {
     2412            let nameValidationTimeout;
     2413           
     2414            nameInput.addEventListener('input', function() {
     2415                // Clear previous validation timeout
     2416                if (nameValidationTimeout) {
     2417                    clearTimeout(nameValidationTimeout);
     2418                }
     2419               
     2420                // Debounce validation
     2421                nameValidationTimeout = setTimeout(() => {
     2422                    const name = this.value.trim();
     2423                    clearEmailError();
     2424                   
     2425                    if (name && !isValidName(name)) {
     2426                        showEmailError('Name must be between 2 and 100 characters.');
     2427                    }
     2428                }, 500);
     2429            });
     2430
     2431            // Handle Enter key
     2432            nameInput.addEventListener('keypress', function(e) {
     2433                if (e.key === 'Enter' && !isSubmitting) {
     2434                    emailForm.dispatchEvent(new Event('submit'));
     2435                }
     2436            });
     2437        }
     2438    }
     2439   
     2440} else if (mxchatChat && mxchatChat.email_collection_enabled) {
    23542441    console.error('Essential elements for email handling are missing:', {
    23552442        emailForm: !!emailForm,
  • mxchat-basic/trunk/js/mxchat-admin.js

    r3341601 r3343848  
    20692069    }
    20702070});
     2071
     2072jQuery(document).ready(function($) {
     2073    var emailDependentFields = [
     2074        '#email_blocker_header_content',
     2075        '#email_blocker_button_text',
     2076        '#enable_name_field',
     2077        '#name_field_placeholder'
     2078    ];
     2079   
     2080    // Add visual indicators
     2081    emailDependentFields.forEach(function(fieldId) {
     2082        var $row = $(fieldId).closest('tr');
     2083        $row.addClass('email-dependent-field');
     2084       
     2085        // Add an icon to show it's dependent
     2086        var $label = $row.find('th label, th');
     2087        $label.prepend('<span class="email-dependent-icon" style="color: #0073aa; margin-right: 5px;">↳</span>');
     2088    });
     2089   
     2090    // Hide initially with opacity for smoother transition
     2091    emailDependentFields.forEach(function(fieldId) {
     2092        $(fieldId).closest('tr').hide().css('opacity', '0');
     2093    });
     2094   
     2095    function toggleEmailFields() {
     2096        var emailEnabled = $('#enable_email_block').is(':checked');
     2097       
     2098        emailDependentFields.forEach(function(fieldId) {
     2099            var $row = $(fieldId).closest('tr');
     2100            if (emailEnabled) {
     2101                $row.slideDown(400).animate({opacity: 1}, 200);
     2102            } else {
     2103                $row.animate({opacity: 0}, 200).slideUp(400);
     2104            }
     2105        });
     2106    }
     2107   
     2108    toggleEmailFields();
     2109    $('#enable_email_block').on('change', toggleEmailFields);
     2110});
     2111
  • mxchat-basic/trunk/mxchat-basic.php

    r3341601 r3343848  
    33 * Plugin Name: MxChat
    44 * Description: AI chatbot for WordPress with OpenAI, Claude, xAI, DeepSeek, live agent, PDF uploads, WooCommerce, and training on website data.
    5  * Version: 2.3.7
     5 * Version: 2.3.8
    66 * Author: MxChat
    77 * Author URI: https://mxchat.ai
     
    1717
    1818// Define plugin version constant for asset versioning
    19 define('MXCHAT_VERSION', '2.3.7');
     19define('MXCHAT_VERSION', '2.3.8');
    2020
    2121function mxchat_load_textdomain() {
     
    5050
    5151/**
    52  * NEW: Create URL click tracking table
     52 * Create URL click tracking table
    5353 */
    5454function mxchat_create_url_clicks_table() {
     
    7676}
    7777
    78 function mxchat_activate() {
     78/**
     79 * FIXED: Robust table creation and column management
     80 */
     81function mxchat_create_chat_transcripts_table() {
    7982    global $wpdb;
     83   
     84    $table_name = $wpdb->prefix . 'mxchat_chat_transcripts';
    8085    $charset_collate = $wpdb->get_charset_collate();
    81 
    82     // Chat Transcripts Table
    83     $chat_transcripts_table = $wpdb->prefix . 'mxchat_chat_transcripts';
    84     $sql_chat_transcripts = "CREATE TABLE $chat_transcripts_table (
     86   
     87    // Create table with ALL columns including user_name from the start
     88    $sql = "CREATE TABLE $table_name (
    8589        id MEDIUMINT(9) NOT NULL AUTO_INCREMENT,
    8690        user_id MEDIUMINT(9) DEFAULT 0,
     
    8993        message TEXT NOT NULL,
    9094        user_email VARCHAR(255) DEFAULT NULL,
     95        user_name VARCHAR(100) DEFAULT NULL,
     96        user_identifier VARCHAR(255) DEFAULT NULL,
     97        originating_page_url TEXT DEFAULT NULL,
     98        originating_page_title VARCHAR(500) DEFAULT NULL,
    9199        timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL,
    92         PRIMARY KEY (id)
     100        PRIMARY KEY (id),
     101        KEY session_id (session_id),
     102        KEY user_email (user_email),
     103        KEY timestamp (timestamp)
    93104    ) $charset_collate;";
     105   
     106    require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
     107    $result = dbDelta($sql);
     108   
     109    // Log the result for debugging
     110    if (empty($result)) {
     111        //error_log("MxChat: dbDelta returned empty result for chat transcripts table");
     112    } else {
     113        //error_log("MxChat: dbDelta result: " . print_r($result, true));
     114    }
     115   
     116    // IMPORTANT: Ensure all columns exist for existing installations
     117    mxchat_ensure_all_columns($table_name);
     118}
     119
     120/**
     121 * IMPROVED: Ensure all required columns exist (for upgrades)
     122 */
     123function mxchat_ensure_all_columns($table_name) {
     124    global $wpdb;
     125   
     126    // First check if table exists
     127    $table_exists = $wpdb->get_var("SHOW TABLES LIKE '$table_name'") === $table_name;
     128    if (!$table_exists) {
     129        //error_log("MxChat: Table $table_name does not exist, cannot add columns");
     130        return;
     131    }
     132   
     133    // Define all required columns and their types
     134    $required_columns = [
     135        'user_identifier' => 'VARCHAR(255) DEFAULT NULL',
     136        'user_email' => 'VARCHAR(255) DEFAULT NULL',
     137        'user_name' => 'VARCHAR(100) DEFAULT NULL',
     138        'originating_page_url' => 'TEXT DEFAULT NULL',
     139        'originating_page_title' => 'VARCHAR(500) DEFAULT NULL'
     140    ];
     141   
     142    // Get existing columns
     143    $existing_columns = $wpdb->get_results("SHOW COLUMNS FROM $table_name");
     144    if (empty($existing_columns)) {
     145        //error_log("MxChat: Could not get columns for table $table_name");
     146        return;
     147    }
     148   
     149    $existing_column_names = array_column($existing_columns, 'Field');
     150   
     151    // Add missing columns
     152    foreach ($required_columns as $column_name => $column_definition) {
     153        if (!in_array($column_name, $existing_column_names)) {
     154            $alter_sql = "ALTER TABLE $table_name ADD COLUMN $column_name $column_definition";
     155            $result = $wpdb->query($alter_sql);
     156           
     157            if ($result === false) {
     158                //error_log("MxChat: Failed to add column $column_name to $table_name. Error: " . $wpdb->last_error);
     159            } else {
     160                //error_log("MxChat: Successfully added column $column_name to $table_name");
     161            }
     162        }
     163    }
     164}
     165
     166function mxchat_activate() {
     167    global $wpdb;
     168    $charset_collate = $wpdb->get_charset_collate();
     169
     170    //error_log("MxChat: Running activation function");
     171
     172    // Create chat transcripts table with improved function
     173    mxchat_create_chat_transcripts_table();
    94174
    95175    // System Prompt Content Table
     
    114194        callback_function VARCHAR(255) NOT NULL,
    115195        similarity_threshold FLOAT DEFAULT 0.85,
     196        enabled TINYINT(1) NOT NULL DEFAULT 1,
    116197        PRIMARY KEY (id)
    117198    ) $charset_collate;";
     
    119200    require_once ABSPATH . 'wp-admin/includes/upgrade.php';
    120201
    121     // Create or update tables
    122     dbDelta($sql_chat_transcripts);
     202    // Create other tables
    123203    dbDelta($sql_system_prompt);
    124204    dbDelta($sql_intents_table);
    125205
    126     // NEW: Create URL click tracking table
     206    // Create URL click tracking table
    127207    mxchat_create_url_clicks_table();
    128208
    129     // Ensure additional columns in `mxchat_chat_transcripts`
    130     mxchat_add_missing_columns($chat_transcripts_table, 'user_identifier', 'VARCHAR(255)');
    131     mxchat_add_missing_columns($chat_transcripts_table, 'user_email', 'VARCHAR(255) DEFAULT NULL');
    132    
    133     // NEW: Add originating page tracking columns
    134     mxchat_add_missing_columns($chat_transcripts_table, 'originating_page_url', 'TEXT DEFAULT NULL');
    135     mxchat_add_missing_columns($chat_transcripts_table, 'originating_page_title', 'VARCHAR(500) DEFAULT NULL');
    136 
    137     // Ensure additional columns in `mxchat_system_prompt_content`
    138     mxchat_add_missing_columns($system_prompt_table, 'embedding_vector', 'LONGTEXT');
    139     mxchat_add_missing_columns($system_prompt_table, 'source_url', 'VARCHAR(255) DEFAULT NULL');
     209    // Ensure additional columns in system prompt table
     210    $existing_system_columns = $wpdb->get_results("SHOW COLUMNS FROM $system_prompt_table");
     211    if (!empty($existing_system_columns)) {
     212        $existing_system_column_names = array_column($existing_system_columns, 'Field');
     213       
     214        if (!in_array('embedding_vector', $existing_system_column_names)) {
     215            $wpdb->query("ALTER TABLE $system_prompt_table ADD COLUMN embedding_vector LONGTEXT");
     216        }
     217        if (!in_array('source_url', $existing_system_column_names)) {
     218            $wpdb->query("ALTER TABLE $system_prompt_table ADD COLUMN source_url VARCHAR(255) DEFAULT NULL");
     219        }
     220    }
    140221
    141222    // Set default thresholds for existing intents
    142223    $wpdb->query("UPDATE {$intents_table} SET similarity_threshold = 0.85 WHERE similarity_threshold IS NULL");
    143     mxchat_add_missing_columns($intents_table, 'enabled', 'TINYINT(1) NOT NULL DEFAULT 1');
    144 
    145     // SETUP CRON JOB HERE (ONCE ON ACTIVATION)
     224   
     225    // Ensure enabled column exists in intents table
     226    $existing_intent_columns = $wpdb->get_results("SHOW COLUMNS FROM $intents_table");
     227    if (!empty($existing_intent_columns)) {
     228        $existing_intent_column_names = array_column($existing_intent_columns, 'Field');
     229       
     230        if (!in_array('enabled', $existing_intent_column_names)) {
     231            $wpdb->query("ALTER TABLE $intents_table ADD COLUMN enabled TINYINT(1) NOT NULL DEFAULT 1");
     232        }
     233    }
     234
     235    // Setup cron jobs
    146236    mxchat_setup_cron_jobs();
    147237
    148     // Use the constant instead of hardcoded version
     238    // Update version
    149239    update_option('mxchat_plugin_version', MXCHAT_VERSION);
     240   
     241    //error_log("MxChat: Activation function completed");
    150242}
    151243
     
    162254        update_option('mxchat_use_fallback_rate_limits', true);
    163255        update_option('mxchat_next_rate_limit_check', time() + 3600);
    164         //error_log('MxChat: WordPress cron disabled, using fallback system');
    165256        return;
    166257    }
     
    173264        update_option('mxchat_use_fallback_rate_limits', true);
    174265        update_option('mxchat_next_rate_limit_check', time() + 3600);
    175         //error_log('MxChat: Failed to schedule cron on activation, using fallback');
    176266    } else {
    177267        // Clear fallback flags if cron scheduling succeeded
    178268        delete_option('mxchat_use_fallback_rate_limits');
    179         //error_log('MxChat: Successfully scheduled cron on activation');
    180269    }
    181270}
     
    192281    delete_option('mxchat_next_rate_limit_check');
    193282    delete_option('mxchat_fallback_check_interval');
    194    
    195     //error_log('MxChat: Cleaned up cron jobs on deactivation');
    196283}
    197284
     
    220307}
    221308
    222 function mxchat_add_missing_columns($table, $column_name, $column_type) {
    223     global $wpdb;
    224     $column_exists = $wpdb->get_results($wpdb->prepare("SHOW COLUMNS FROM $table LIKE %s", $column_name));
    225     if (empty($column_exists)) {
    226         $wpdb->query("ALTER TABLE $table ADD COLUMN $column_name $column_type");
    227     }
    228 }
    229 
     309/**
     310 * FIXED: Robust update checking with proper version handling
     311 */
    230312function mxchat_check_for_update() {
     313    global $wpdb; // CRITICAL: Declare this at the top
     314   
    231315    try {
    232         $current_version = get_option('mxchat_plugin_version');
     316        $current_version = get_option('mxchat_plugin_version', '0.0.0');
    233317        $plugin_version = MXCHAT_VERSION;
    234318
     319        // Always run activation to ensure tables exist (safe for existing installations)
    235320        if ($current_version !== $plugin_version) {
     321            //error_log("MxChat: Version change detected: $current_version -> $plugin_version");
     322           
    236323            // Run live agent update BEFORE updating the stored version
    237324            mxchat_handle_live_agent_update();
    238325           
    239             // Run existing update processes
     326            // Run activation (this will create/update all tables and columns)
    240327            mxchat_activate();
     328           
     329            // Run migration functions
    241330            mxchat_migrate_live_agent_status();
    242331
    243             // Add the new cleanup function for version 2.1.8
     332            // Add the cleanup function for version 2.1.8
    244333            if (version_compare($current_version, '2.1.8', '<')) {
    245334                $deleted = mxchat_cleanup_orphaned_chat_history();
    246335            }
    247336
    248             // Update version LAST so the live agent update logic can work
     337            // Update version LAST
    249338            update_option('mxchat_plugin_version', $plugin_version);
    250         }
     339           
     340            //error_log("MxChat: Updated from version $current_version to $plugin_version");
     341        }
     342       
     343        // CRITICAL: Always ensure tables exist, even if version matches
     344        // This handles cases where tables were manually deleted
     345        $table_name = $wpdb->prefix . 'mxchat_chat_transcripts';
     346        $table_exists = $wpdb->get_var("SHOW TABLES LIKE '$table_name'") === $table_name;
     347       
     348        if (!$table_exists) {
     349            //error_log("MxChat: Chat transcripts table missing, recreating...");
     350            mxchat_activate(); // Run full activation instead of just table creation
     351        }
     352       
    251353    } catch (Exception $e) {
    252354        //error_log('MxChat update error: ' . $e->getMessage());
    253355        // Don't update version if there was an error
     356    }
     357}
     358
     359/**
     360 * CRITICAL: Ensure tables exist on every load for fresh installations
     361 */
     362function mxchat_ensure_tables_exist() {
     363    global $wpdb;
     364   
     365    // Only run for admin users to avoid performance impact
     366    if (!current_user_can('administrator')) {
     367        return;
     368    }
     369   
     370    $table_name = $wpdb->prefix . 'mxchat_chat_transcripts';
     371    $table_exists = $wpdb->get_var("SHOW TABLES LIKE '$table_name'") === $table_name;
     372   
     373    if (!$table_exists) {
     374        //error_log("MxChat: Tables missing on admin load, running activation");
     375        mxchat_activate();
    254376    }
    255377}
     
    288410                // Also delete related metadata
    289411                delete_option("mxchat_email_{$session_id}");
     412                delete_option("mxchat_name_{$session_id}");
    290413                delete_option("mxchat_agent_name_{$session_id}");
    291414                $count++;
     
    364487    mxchat_check_for_update();
    365488   
     489    // CRITICAL: Ensure tables exist (for fresh installations that don't trigger activation hook)
     490    add_action('admin_init', 'mxchat_ensure_tables_exist', 1);
     491   
    366492    // Add fallback rate limit check
    367493    add_action('init', 'mxchat_check_fallback_rate_limits', 5);
  • mxchat-basic/trunk/readme.txt

    r3341601 r3343848  
    66Tested up to: 6.8
    77Requires PHP: 7.2
    8 Stable tag: 2.3.7
     8Stable tag: 2.3.8
    99License: GPLv2 or later
    1010License URI: https://www.gnu.org/licenses/gpl-2.0.html
     
    3434✅ **Extensive Add-On Ecosystem**: Forms, moderation, recommendations, theme customization, and more 
    3535
    36 ### 2.3.7
    37 🤖 **New Models**
    38 - Added **GPT-5 family** models:
    39   - **GPT-5** – Flagship for coding, reasoning, and agentic tasks across domains.
    40   - **GPT-5 Mini** – Faster, more cost-efficient for well-defined tasks and precise prompts.
    41   - **GPT-5 Nano** – Fastest and most affordable; ideal for summarization and classification.
     36## 🔥 What's New in Version 2.3.8
     37🔧 **Fixed Extra Characters in Knowledgebase** – Prevented extra backslashes from appearing when editing content in the knowledgebase.
     38👤 **Enhanced Require Email to Chat Form** – Added an optional name field to the require email to chat form. Now, at the top of chat transcripts, it will show email + name if enabled.
     39💬 **Improved Slack Channel Naming** – When notifying live agents via Slack, the channel name will now be: the user's email if logged in; their email if require email to chat is enabled; otherwise, the chat ID.
    4240
    4341## 🚀 Core Features That Set MxChat Apart
     
    175173== Changelog ==
    176174
     175= 2.3.8 - August 12, 2025 =
     176- Fixed extra backslashes appearing in knowledgebase content during editing.
     177- Added optional name field to Require Email to Chat form; transcripts now display email and name if enabled.
     178- Updated Slack channel naming for live agent notifications: uses user's email if logged in, email if Require Email to Chat is enabled, or chat ID otherwise.
     179
    177180= 2.3.7 - August 8, 2025 =
    178181- New Models: Added GPT-5 family (GPT-5, GPT-5 Mini, GPT-5 Nano) to expand capabilities with faster, smarter, and more cost-efficient options.
    179 
    180182= 2.3.6 - August 6, 2025 =
    181183- Bug Fix: Fixed streaming fallback to properly display responses when streaming fails, preventing blank chat bubbles.
     
    505507== Upgrade Notice ==
    506508
    507 = 2.3.7 =
    508 - New Models: Added GPT-5 family (GPT-5, GPT-5 Mini, GPT-5 Nano) for faster, smarter, and more versatile AI responses.
     509= 2.3.8 =
     510- Fixed extra backslashes appearing in knowledgebase content during editing.
     511- Added optional name field to Require Email to Chat form; transcripts now display email and name if enabled.
     512- Updated Slack channel naming for live agent notifications: uses user's email if logged in, email if Require Email to Chat is enabled, or chat ID otherwise.
    509513
    510514== License & Warranty ==
Note: See TracChangeset for help on using the changeset viewer.