esc_html(__('You do not have permission to perform this action.', 'ai-product-assistant')))); } } /** * Do Settings Sections For Group * * @param string $page * @param array $fields */ public function do_settings_sections_for_group($page, $fields) { global $wp_settings_fields; if (!isset($wp_settings_fields[$page])) { return; } echo ''; echo ''; foreach ($wp_settings_fields[$page] as $section => $section_fields) { foreach ($section_fields as $field_id => $field) { if (in_array($field_id, $fields)) { echo ''; echo ''; echo ''; echo ''; } } } echo ''; echo ''; } /** * Create statistics database table if it doesn't exist */ public function create_statistics_table() { global $wpdb; $table_name = $wpdb->prefix . 'aipa_statistics'; // Check if table exists (necessary system check with prepared statement) // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching if($wpdb->get_var($wpdb->prepare("SHOW TABLES LIKE %s", $table_name)) != $table_name) { $charset_collate = $wpdb->get_charset_collate(); $sql = "CREATE TABLE $table_name ( id mediumint(9) NOT NULL AUTO_INCREMENT, user_role varchar(50) NOT NULL DEFAULT 'guest', timestamp datetime DEFAULT CURRENT_TIMESTAMP NOT NULL, api_provider varchar(100) NOT NULL, api_model varchar(100) NOT NULL, request_type varchar(20) NOT NULL, request_prompt text NOT NULL, request_chars int(11) NOT NULL, request_tokens int(11) NOT NULL, response_text text NOT NULL, response_chars int(11) NOT NULL, response_tokens int(11) NOT NULL, execution_time float NOT NULL, PRIMARY KEY (id) ) $charset_collate;"; require_once(ABSPATH . 'wp-admin/includes/upgrade.php'); dbDelta($sql); } } /** * Handle Statistics export */ public function handle_statistics_export() { if (isset($_GET['action']) && $_GET['action'] === 'export_statistics' && isset($_GET['page']) && $_GET['page'] === 'ai-product-assistant') { if (!isset($_GET['nonce']) || !wp_verify_nonce(sanitize_text_field(wp_unslash($_GET['nonce'])), 'aipa_admin_nonce')) { wp_die(esc_html(__('Security check failed.', 'ai-product-assistant'))); } if (!current_user_can('manage_options')) { wp_die(esc_html(__('You do not have sufficient permissions to access this page.', 'ai-product-assistant'))); } $time_range = isset($_GET['time_range']) ? sanitize_text_field(wp_unslash($_GET['time_range'])) : 'all'; global $wpdb; $table_name = $wpdb->prefix . 'aipa_statistics'; // Build query with predefined conditions (no user input) $sql = "SELECT * FROM {$wpdb->prefix}aipa_statistics "; switch ($time_range) { case 'today': $sql .= "WHERE DATE(timestamp) = CURDATE() "; break; case 'yesterday': $sql .= "WHERE DATE(timestamp) = DATE_SUB(CURDATE(), INTERVAL 1 DAY) "; break; case '7days': $sql .= "WHERE timestamp >= DATE_SUB(NOW(), INTERVAL 7 DAY) "; break; case '30days': $sql .= "WHERE timestamp >= DATE_SUB(NOW(), INTERVAL 30 DAY) "; break; default: // No where clause for 'all' option break; } $sql .= "ORDER BY timestamp DESC"; // Execute query (safe because no user input is interpolated) // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching,WordPress.DB.PreparedSQL.NotPrepared $stats = $wpdb->get_results($sql, ARRAY_A); header('Content-Type: text/csv; charset=utf-8'); header('Content-Disposition: attachment; filename=aipa-statistics-' . gmdate('Y-m-d') . '.csv'); // Use WordPress-style output for CSV echo "\xEF\xBB\xBF"; // BOM for UTF-8 // Output CSV header $header = array( 'ID', 'User Role', 'Timestamp', 'API Provider', 'API Model', 'Request Type', 'Request Prompt', 'Request Chars', 'Request Tokens', 'Response Text', 'Response Chars', 'Response Tokens', 'Execution Time (s)' ); echo '"' . implode('","', array_map('esc_attr', $header)) . '"' . "\n"; // Output CSV data foreach ($stats as $row) { $csv_row = array( $row['id'], $row['user_role'], $row['timestamp'], $row['api_provider'], $row['api_model'], $row['request_type'], $row['request_prompt'], $row['request_chars'], $row['request_tokens'], $row['response_text'], $row['response_chars'], $row['response_tokens'], $row['execution_time'] ); echo '"' . implode('","', array_map('esc_attr', $csv_row)) . '"' . "\n"; } exit; } } /** * Sanitize settings */ public function sanitize_settings($input) { $sanitized_input = array(); // API Provider if (isset($input['api_provider'])) { $sanitized_input['api_provider'] = sanitize_text_field($input['api_provider']); } // API URL if (isset($input['api_url'])) { $sanitized_input['api_url'] = esc_url_raw($input['api_url']); } // API Model if (isset($input['api_model'])) { $sanitized_input['api_model'] = sanitize_text_field($input['api_model']); } // Custom Model (if needed) if (isset($input['api_model_custom']) && $input['api_model'] === 'custom') { $sanitized_input['api_model'] = sanitize_text_field($input['api_model_custom']); } // Format Template if (isset($input['format_template'])) { $sanitized_input['format_template'] = sanitize_text_field($input['format_template']); } // API Key if (isset($input['api_key'])) { $sanitized_input['api_key'] = sanitize_text_field($input['api_key']); } // Search Fields $sanitized_input['search_fields'] = array( 'title' => isset($input['search_fields']['title']) ? true : false, 'short_description' => isset($input['search_fields']['short_description']) ? true : false, 'content' => isset($input['search_fields']['content']) ? true : false, 'categories' => isset($input['search_fields']['categories']) ? true : false, 'tags' => isset($input['search_fields']['tags']) ? true : false, 'brand' => isset($input['search_fields']['brand']) ? true : false, 'weight' => isset($input['search_fields']['weight']) ? true : false, 'dimensions' => isset($input['search_fields']['dimensions']) ? true : false, 'variation_data' => isset($input['search_fields']['variation_data']) ? true : false, 'attributes' => isset($input['search_fields']['attributes']) ? true : false, 'regular_price' => isset($input['search_fields']['regular_price']) ? true : false, 'sale_price' => isset($input['search_fields']['sale_price']) ? true : false ); // Add custom fields to search fields if (isset($input['search_fields'])) { foreach ($input['search_fields'] as $key => $value) { if (strpos($key, 'custom_') === 0) { $sanitized_input['search_fields'][$key] = true; } } } // Custom Fields if (isset($input['custom_fields'])) { // Decode JSON with UTF-8 encoding $json_str = stripslashes($input['custom_fields']); $custom_fields = json_decode($json_str, true); if (is_array($custom_fields)) { $sanitized_custom_fields = array(); foreach ($custom_fields as $field) { if (isset($field['meta_key']) && isset($field['description'])) { // Preserve UTF-8 characters while still sanitizing $meta_key = trim($field['meta_key']); $meta_key = wp_strip_all_tags($meta_key); // Remove control characters but keep all other Unicode characters // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_key $meta_key = preg_replace('/[\x00-\x1F\x7F]/u', '', $meta_key); $sanitized_custom_fields[] = array( // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_key 'meta_key' => $meta_key, 'description' => sanitize_text_field($field['description']) ); } } $sanitized_input['custom_fields'] = $sanitized_custom_fields; } } // Show Out of Stock $sanitized_input['show_out_of_stock'] = isset($input['show_out_of_stock']) ? true : false; // Show Explanation $sanitized_input['show_explanation'] = isset($input['show_explanation']) ? true : false; // AI Explanation Icon if (isset($input['explanation_icon'])) { $sanitized_input['explanation_icon'] = sanitize_text_field($input['explanation_icon']); } // Show Add to Cart $sanitized_input['show_add_to_cart'] = isset($input['show_add_to_cart']) ? true : false; // Use Native Template $sanitized_input['use_native_template'] = isset($input['use_native_template']) ? true : false; // Search UI Customization if (isset($input['search_modal_title'])) { $sanitized_input['search_modal_title'] = sanitize_text_field($input['search_modal_title']); } if (isset($input['search_modal_description'])) { $sanitized_input['search_modal_description'] = sanitize_text_field($input['search_modal_description']); } if (isset($input['search_placeholder'])) { $sanitized_input['search_placeholder'] = sanitize_text_field($input['search_placeholder']); } if (isset($input['voice_button_text'])) { $sanitized_input['voice_button_text'] = sanitize_text_field($input['voice_button_text']); } if (isset($input['search_button_text'])) { $sanitized_input['search_button_text'] = sanitize_text_field($input['search_button_text']); } // Search Button Icon type $sanitized_input['button_icon_type'] = isset($input['button_icon_type']) ? sanitize_text_field($input['button_icon_type']) : 'text'; $sanitized_input['button_icon'] = isset($input['button_icon']) ? sanitize_text_field($input['button_icon']) : 'AI Search'; $sanitized_input['button_icon_image'] = isset($input['button_icon_image']) ? esc_url_raw($input['button_icon_image']) : ''; // Search Button CSS if (isset($input['button_css'])) { $sanitized_input['button_css'] = wp_kses($input['button_css'], array()); } // Show Floating Button $sanitized_input['show_floating_button'] = isset($input['show_floating_button']) ? true : false; $sanitized_input['search_button_icon_type'] = isset($input['search_button_icon_type']) ? sanitize_text_field($input['search_button_icon_type']) : 'text'; $sanitized_input['search_button_icon'] = isset($input['search_button_icon']) ? sanitize_text_field($input['search_button_icon']) : 'AI'; $sanitized_input['search_button_icon_image'] = isset($input['search_button_icon_image']) ? esc_url_raw($input['search_button_icon_image']) : ''; if (isset($input['search_button_css'])) { $sanitized_input['search_button_css'] = wp_kses($input['search_button_css'], array()); } // Prompt Settings if (isset($input['prompt_prefix'])) { $sanitized_input['prompt_prefix'] = sanitize_textarea_field($input['prompt_prefix']); } if (isset($input['prompt_suffix'])) { $sanitized_input['prompt_suffix'] = sanitize_textarea_field($input['prompt_suffix']); } // Cart Analysis Settings $sanitized_input['enable_cart_analysis'] = isset($input['enable_cart_analysis']) ? true : false; // Cart Analysis UI Customization if (isset($input['cart_analysis_title'])) { $sanitized_input['cart_analysis_title'] = sanitize_text_field($input['cart_analysis_title']); } if (isset($input['cart_analysis_description'])) { $sanitized_input['cart_analysis_description'] = sanitize_text_field($input['cart_analysis_description']); } if (isset($input['cart_analysis_placeholder'])) { $sanitized_input['cart_analysis_placeholder'] = sanitize_text_field($input['cart_analysis_placeholder']); } if (isset($input['cart_analysis_button_text'])) { $sanitized_input['cart_analysis_button_text'] = sanitize_text_field($input['cart_analysis_button_text']); } if (isset($input['cart_analysis_css'])) { $sanitized_input['cart_analysis_css'] = wp_kses($input['cart_analysis_css'], array()); } // Description Length Limit if (isset($input['description_length_limit'])) { $sanitized_input['description_length_limit'] = max(1, intval($input['description_length_limit'])); } else { $sanitized_input['description_length_limit'] = 500; } // Short Description Length Limit if (isset($input['short_description_length_limit'])) { $sanitized_input['short_description_length_limit'] = max(1, intval($input['short_description_length_limit'])); } else { $sanitized_input['short_description_length_limit'] = 200; } // Search Batch Size if (isset($input['search_batch_size'])) { $sanitized_input['search_batch_size'] = intval($input['search_batch_size']); } else { $sanitized_input['search_batch_size'] = 100; // Default value } // Always enable deep search $sanitized_input['enable_deep_search'] = true; // Max Batches if (isset($input['max_batches'])) { $sanitized_input['max_batches'] = intval($input['max_batches']); } else { $batch_size = isset($sanitized_input['search_batch_size']) ? intval($sanitized_input['search_batch_size']) : 100; $product_count = (int) wp_count_posts('product')->publish; $sanitized_input['max_batches'] = $product_count > 0 ? ceil($product_count / $batch_size) : 1; } // Brute Force Search (Pro only; default false = use Smart Search) $sanitized_input['enable_brute_force_search'] = isset($input['enable_brute_force_search']) ? true : false; // AI Temperature (Pro only; default 0.2; range 0.0–2.0) $ai_temperature = isset($input['ai_temperature']) ? (float) $input['ai_temperature'] : 0.2; $sanitized_input['ai_temperature'] = max(0.0, min(2.0, $ai_temperature)); // AI Max Tokens (Pro only; default 4096; range 256–8192) $ai_max_tokens = isset($input['ai_max_tokens']) ? (int) $input['ai_max_tokens'] : 4096; $sanitized_input['ai_max_tokens'] = max(256, min(8192, $ai_max_tokens)); // Product Assistant Settings $sanitized_input['show_product_assistant'] = isset($input['show_product_assistant']) ? true : false; if (isset($input['product_assistant_title'])) { $sanitized_input['product_assistant_title'] = sanitize_text_field($input['product_assistant_title']); } if (isset($input['product_assistant_description'])) { $sanitized_input['product_assistant_description'] = sanitize_text_field($input['product_assistant_description']); } if (isset($input['product_assistant_placeholder'])) { $sanitized_input['product_assistant_placeholder'] = sanitize_text_field($input['product_assistant_placeholder']); } if (isset($input['product_assistant_button_text'])) { $sanitized_input['product_assistant_button_text'] = sanitize_text_field($input['product_assistant_button_text']); } if (isset($input['product_assistant_button_css'])) { $sanitized_input['product_assistant_button_css'] = wp_kses($input['product_assistant_button_css'], array()); } return $sanitized_input; } }