admin_url('admin-ajax.php'),
'nonce' => wp_create_nonce('aipa_product_assistant_nonce'),
'analyzing_text' => __('Analyzing...', 'ai-product-assistant'),
'assistant_placeholder' => $default_placeholder,
'assistant_button' => $default_button_text,
'assistant_title' => $default_title,
'assistant_description' => $default_description,
'error_message' => __('Something went wrong. Please try again.', 'ai-product-assistant'),
'empty_query_message' => __('Please enter a question.', 'ai-product-assistant'),
'aipa_service_error_message' => __('Sorry, AI feature is temporarily unavailable. Please try again later.', 'ai-product-assistant'),
'login_url' => function_exists('wc_get_page_permalink') ? wc_get_page_permalink('myaccount') : wp_login_url(get_permalink()),
'login_text' => __('Log in here', 'ai-product-assistant'),
));
// Add custom CSS
$button_css = isset($options['product_assistant_button_css']) ? $options['product_assistant_button_css'] : '';
if (!empty($button_css)) {
wp_add_inline_style('aipa-product-assistant-css', '.aipa-product-assistant-btn {' . esc_html($button_css) . '}');
}
}
}
/**
* Add product assistant button on product page
*/
public function add_product_assistant_button() {
global $product;
if ($product) {
$options = get_option('aipa_settings');
$button_text = isset($options['product_assistant_button_text']) ? $options['product_assistant_button_text'] : __('Ask AI', 'ai-product-assistant');
echo '
';
echo '';
echo '
';
// Add modal window HTML
$this->add_product_assistant_modal();
}
}
/**
* Add product assistant modal window
*/
public function add_product_assistant_modal() {
$options = get_option('aipa_settings');
$title = isset($options['product_assistant_title']) ? $options['product_assistant_title'] : __('AI Product Assistant', 'ai-product-assistant');
$description = isset($options['product_assistant_description']) ? $options['product_assistant_description'] : __('Ask AI about this product', 'ai-product-assistant');
$placeholder = isset($options['product_assistant_placeholder']) ? $options['product_assistant_placeholder'] : __('e.g., Is this product suitable for beginners?', 'ai-product-assistant');
$button_text = isset($options['product_assistant_button_text']) ? $options['product_assistant_button_text'] : __('Ask AI', 'ai-product-assistant');
?>
__('Please log in to use AI product assistant feature.', 'ai-product-assistant'),
'code' => 'auth_required'
));
}
$query = isset($_POST['query']) ? sanitize_text_field(wp_unslash($_POST['query'])) : '';
$product_id = isset($_POST['product_id']) ? intval($_POST['product_id']) : 0;
AIPA_Debug::log(AIPA_Debug::LEVEL_INFO, 'Product_Assistant', 'AJAX product assistant request received', array('product_id' => $product_id, 'query_length' => strlen($query)));
if (empty($query)) {
AIPA_Debug::log(AIPA_Debug::LEVEL_WARNING, 'Product_Assistant', 'Empty query provided');
wp_send_json_error(array(
'message' => __('Please enter a question.', 'ai-product-assistant')
));
}
if (empty($product_id)) {
AIPA_Debug::log(AIPA_Debug::LEVEL_WARNING, 'Product_Assistant', 'Invalid product ID provided');
wp_send_json_error(array(
'message' => __('Invalid product ID.', 'ai-product-assistant')
));
}
// Get product data
$product = wc_get_product($product_id);
if (!$product) {
AIPA_Debug::log(AIPA_Debug::LEVEL_WARNING, 'Product_Assistant', 'Product not found', array('product_id' => $product_id));
wp_send_json_error(array(
'message' => __('Product not found.', 'ai-product-assistant')
));
}
// Build product data for AI analysis
$product_data = $this->get_product_data_for_analysis($product);
// Call API for analysis
try {
$api = new AIPA_API();
$result = $this->call_api_for_product_analysis($query, $product_data);
if (is_wp_error($result)) {
AIPA_Debug::log(AIPA_Debug::LEVEL_ERROR, 'Product_Assistant', 'API call returned error in AJAX handler', array(
'error_code' => $result->get_error_code(),
'error_message' => $result->get_error_message()
));
wp_send_json_error(array(
'message' => $result->get_error_message(),
'code' => $result->get_error_code()
));
return;
}
// Format result HTML
$html = $this->format_analysis_result($result);
if (empty($html)) {
AIPA_Debug::log(AIPA_Debug::LEVEL_WARNING, 'Product_Assistant', 'Empty HTML after formatting');
$html = '' . __('No analysis results available.', 'ai-product-assistant') . '
';
}
AIPA_Debug::log(AIPA_Debug::LEVEL_INFO, 'Product_Assistant', 'AJAX response successful', array(
'html_length' => strlen($html)
));
wp_send_json_success(array(
'html' => $html
));
} catch (Exception $e) {
AIPA_Debug::log(AIPA_Debug::LEVEL_ERROR, 'Product_Assistant', 'Exception in AJAX handler', array(
'exception' => $e->getMessage(),
'trace' => $e->getTraceAsString()
));
wp_send_json_error(array(
'message' => __('An error occurred while processing your request. Please try again.', 'ai-product-assistant')
));
}
}
/**
* Get product data for AI analysis
*/
private function get_product_data_for_analysis($product) {
$options = get_option('aipa_settings');
$search_fields = isset($options['search_fields']) ? $options['search_fields'] : array();
$description_length_limit = isset($options['description_length_limit']) ? intval($options['description_length_limit']) : 500;
$short_description_length_limit = isset($options['short_description_length_limit']) ? intval($options['short_description_length_limit']) : 200;
// Debug logging
AIPA_Debug::log(AIPA_Debug::LEVEL_DEBUG, 'Product_Assistant', 'Configuration loaded', array('search_fields' => $search_fields, 'description_limit' => $description_length_limit));
$product_data = array(
'id' => $product->get_id(),
'data' => array()
);
// Add product fields
if (isset($search_fields['title']) && $search_fields['title']) {
$product_data['data']['title'] = $product->get_name();
}
if (isset($search_fields['content']) && $search_fields['content']) {
$content = $product->get_description();
$product_data['data']['content'] = substr($content, 0, $description_length_limit);
}
if (isset($search_fields['short_description']) && $search_fields['short_description']) {
$short_description = $product->get_short_description();
$product_data['data']['short_description'] = substr($short_description, 0, $short_description_length_limit);
}
if (isset($search_fields['categories']) && $search_fields['categories']) {
$categories = array();
$terms = get_the_terms($product->get_id(), 'product_cat');
if ($terms && !is_wp_error($terms)) {
foreach ($terms as $term) {
$categories[] = $term->name;
}
}
$product_data['data']['categories'] = implode(', ', $categories);
}
if (isset($search_fields['attributes']) && $search_fields['attributes']) {
$attributes = array();
$product_attributes = $product->get_attributes();
if (!empty($product_attributes)) {
foreach ($product_attributes as $attribute) {
if ($attribute->is_taxonomy()) {
$taxonomy = $attribute->get_taxonomy_object();
$attribute_name = $taxonomy->attribute_label;
$values = array();
$terms = $attribute->get_terms();
if (!empty($terms)) {
foreach ($terms as $term) {
$values[] = $term->name;
}
}
$attributes[$attribute_name] = implode(', ', $values);
} else {
$attribute_name = $attribute->get_name();
$attributes[$attribute_name] = implode(', ', $attribute->get_options());
}
}
}
$product_data['data']['attributes'] = $attributes;
}
if (isset($search_fields['regular_price']) && $search_fields['regular_price']) {
$product_data['data']['regular_price'] = $product->get_regular_price();
}
if (isset($search_fields['sale_price']) && $search_fields['sale_price']) {
$product_data['data']['sale_price'] = $product->get_sale_price();
}
// Add tags if selected
if (isset($search_fields['tags']) && $search_fields['tags']) {
$tags = array();
$terms = get_the_terms($product->get_id(), 'product_tag');
if ($terms && !is_wp_error($terms)) {
foreach ($terms as $term) {
$tags[] = $term->name;
}
}
$product_data['data']['tags'] = implode(', ', $tags);
}
// Add brand if selected
if (isset($search_fields['brand']) && $search_fields['brand']) {
$brands = array();
$terms = get_the_terms($product->get_id(), 'product_brand');
if ($terms && !is_wp_error($terms)) {
foreach ($terms as $term) {
$brands[] = $term->name;
}
}
$product_data['data']['brand'] = implode(', ', $brands);
}
// Add weight if selected
if (isset($search_fields['weight']) && $search_fields['weight']) {
$weight = $product->get_weight();
if ($weight) {
$weight_unit = get_option('woocommerce_weight_unit');
$product_data['data']['weight'] = $weight . ' ' . $weight_unit;
}
}
// Add dimensions if selected
if (isset($search_fields['dimensions']) && $search_fields['dimensions']) {
$dimensions = array();
$length = $product->get_length();
$width = $product->get_width();
$height = $product->get_height();
if ($length || $width || $height) {
$dimension_unit = get_option('woocommerce_dimension_unit');
$dimensions_text = '';
if ($length) $dimensions_text .= $length;
if ($width) $dimensions_text .= ' x ' . $width;
if ($height) $dimensions_text .= ' x ' . $height;
$product_data['data']['dimensions'] = trim($dimensions_text, ' x ') . ' ' . $dimension_unit;
}
}
// Add variation data if selected and product is variable
if (isset($search_fields['variation_data']) && $search_fields['variation_data'] && $product->is_type('variable')) {
$variations = array();
$variation_ids = $product->get_children();
foreach ($variation_ids as $variation_id) {
$variation = wc_get_product($variation_id);
if ($variation) {
$variation_data = array(
'id' => $variation_id,
'attributes' => $variation->get_variation_attributes(),
'price' => $variation->get_price(),
'in_stock' => $variation->is_in_stock()
);
$variations[] = $variation_data;
}
}
$product_data['data']['variation_data'] = $variations;
}
// Add custom fields if configured
if (isset($options['custom_fields']) && is_array($options['custom_fields'])) {
$all_meta = get_post_meta($product->get_id());
$custom_meta = array();
// Record all selected custom fields
foreach ($options['custom_fields'] as $custom_field) {
if (isset($custom_field['meta_key'])) {
$meta_key = $custom_field['meta_key'];
if (isset($all_meta[$meta_key])) {
$meta_value = maybe_unserialize($all_meta[$meta_key][0]);
if (!empty($meta_value)) {
$custom_meta[$meta_key] = $meta_value;
}
}
}
}
if (!empty($custom_meta)) {
$product_data['data']['custom_meta'] = $custom_meta;
}
}
return $product_data;
}
/**
* Call API for product analysis
*/
private function call_api_for_product_analysis($query, $product_data) {
// Debug logging - log final product data
AIPA_Debug::log(AIPA_Debug::LEVEL_DEBUG, 'Product_Assistant', 'Calling API for product analysis', array('query' => $query, 'product_id' => $product_data['id']));
try {
// Create WP_REST_Request instance
$request = new WP_REST_Request('POST', '/aipa/v1/product-assistant');
$request->set_param('query', $query);
$request->set_param('product_data', $product_data);
// Send request
$response = rest_do_request($request);
// Handle errors
if (is_wp_error($response)) {
AIPA_Debug::log(AIPA_Debug::LEVEL_ERROR, 'Product_Assistant', 'REST request returned WP_Error', array(
'error_code' => $response->get_error_code(),
'error_message' => $response->get_error_message()
));
return $response;
}
// Get response data
$data = $response->get_data();
// Log the response data structure
AIPA_Debug::log(AIPA_Debug::LEVEL_DEBUG, 'Product_Assistant', 'REST response received', array(
'has_data' => !empty($data),
'has_analysis' => isset($data['analysis']),
'data_keys' => is_array($data) ? array_keys($data) : 'not_array'
));
// Check if the response contains error information (from wp_send_json_error)
if (isset($data['code']) && isset($data['message'])) {
AIPA_Debug::log(AIPA_Debug::LEVEL_ERROR, 'Product_Assistant', 'REST API returned error response', array(
'error_code' => $data['code'],
'error_message' => $data['message']
));
return new WP_Error($data['code'], $data['message']);
}
if (empty($data) || !isset($data['analysis'])) {
AIPA_Debug::log(AIPA_Debug::LEVEL_ERROR, 'Product_Assistant', 'Invalid response structure', array(
'data' => $data
));
return new WP_Error('invalid_response', __('Invalid response from AI API.', 'ai-product-assistant'));
}
return $data;
} catch (Exception $e) {
AIPA_Debug::log(AIPA_Debug::LEVEL_ERROR, 'Product_Assistant', 'Exception in call_api_for_product_analysis', array(
'exception' => $e->getMessage(),
'trace' => $e->getTraceAsString()
));
return new WP_Error('api_exception', $e->getMessage());
}
}
/**
* Format analysis result as HTML
*/
private function format_analysis_result($result) {
$output = '';
try {
if (empty($result)) {
AIPA_Debug::log(AIPA_Debug::LEVEL_WARNING, 'Product_Assistant', 'Empty result in format_analysis_result');
return $output;
}
// Log the result structure
AIPA_Debug::log(AIPA_Debug::LEVEL_DEBUG, 'Product_Assistant', 'Formatting analysis result', array(
'has_analysis' => isset($result['analysis']),
'has_features' => isset($result['features']),
'has_recommendations' => isset($result['recommendations']),
'features_count' => isset($result['features']) ? count($result['features']) : 0,
'recommendations_count' => isset($result['recommendations']) ? count($result['recommendations']) : 0
));
// Main analysis result
if (isset($result['analysis']) && !empty($result['analysis'])) {
$output .= '';
$output .= '
' . __('Analysis', 'ai-product-assistant') . '
';
$output .= '
' . nl2br(esc_html($result['analysis'])) . '
';
$output .= '
';
}
// Display features list (if any)
if (!empty($result['features']) && is_array($result['features'])) {
$output .= '';
$output .= '
' . __('Key Features', 'ai-product-assistant') . '
';
$output .= '
';
foreach ($result['features'] as $feature) {
if (is_string($feature)) {
$output .= '- ' . esc_html($feature) . '
';
}
}
$output .= '
';
$output .= '
';
}
// Display recommendations (if any)
if (!empty($result['recommendations']) && is_array($result['recommendations'])) {
$output .= '';
$output .= '
' . __('Recommendations', 'ai-product-assistant') . '
';
$output .= '
';
foreach ($result['recommendations'] as $recommendation) {
if (is_string($recommendation)) {
$output .= '- ' . esc_html($recommendation) . '
';
}
}
$output .= '
';
$output .= '
';
}
return $output;
} catch (Exception $e) {
AIPA_Debug::log(AIPA_Debug::LEVEL_ERROR, 'Product_Assistant', 'Exception in format_analysis_result', array(
'exception' => $e->getMessage(),
'trace' => $e->getTraceAsString()
));
return '' . __('Error formatting response.', 'ai-product-assistant') . '
';
}
}
/**
* Render product assistant button shortcode
*/
public function render_product_assistant_button_shortcode($atts) {
$atts = shortcode_atts(array(
'product_id' => 0,
'button_text' => '',
), $atts);
$product_id = intval($atts['product_id']);
if (empty($product_id)) {
return '' . __('Error: Product ID is required for the product assistant button.', 'ai-product-assistant') . '
';
}
// Check if product exists
$product = wc_get_product($product_id);
if (!$product) {
return '' . __('Error: Product not found.', 'ai-product-assistant') . '
';
}
// Get settings
$options = get_option('aipa_settings');
$default_button_text = isset($options['product_assistant_button_text']) ? $options['product_assistant_button_text'] : __('Ask AI', 'ai-product-assistant');
$button_text = !empty($atts['button_text']) ? $atts['button_text'] : $default_button_text;
// Ensure scripts and styles are loaded
wp_enqueue_style('aipa-product-assistant-css', AIPA_PLUGIN_URL . 'assets/css/product-assistant.css', array('aipa-frontend-css'), AIPA_VERSION);
wp_enqueue_script('aipa-product-assistant-js', AIPA_PLUGIN_URL . 'assets/js/product-assistant.js', array('jquery'), AIPA_VERSION, true);
// Ensure frontend and cart scripts are also loaded
wp_enqueue_script('aipa-frontend-js', AIPA_PLUGIN_URL . 'assets/js/frontend.js', array('jquery'), AIPA_VERSION, true);
wp_enqueue_script('aipa-cart-analysis-js', AIPA_PLUGIN_URL . 'assets/js/cart-analysis.js', array('jquery'), AIPA_VERSION, true);
// Generate unique button ID
$button_id = 'aipa-product-assistant-btn-' . uniqid();
// Output button HTML
$output = '';
$output .= '';
$output .= '
';
// Add modal window HTML (if not already on page)
if (!has_action('wp_footer', array($this, 'add_product_assistant_modal'))) {
add_action('wp_footer', array($this, 'add_product_assistant_modal'));
}
return $output;
}
/**
* Render product assistant form shortcode
*/
public function render_product_assistant_form_shortcode($atts) {
$atts = shortcode_atts(array(
'product_id' => 0,
'title' => '',
'description' => '',
'placeholder' => '',
'button_text' => '',
), $atts);
$product_id = intval($atts['product_id']);
if (empty($product_id)) {
return '' . __('Error: Product ID is required for the product assistant form.', 'ai-product-assistant') . '
';
}
// Check if product exists
$product = wc_get_product($product_id);
if (!$product) {
return '' . __('Error: Product not found.', 'ai-product-assistant') . '
';
}
// Get settings
$options = get_option('aipa_settings');
$default_title = isset($options['product_assistant_title']) ? $options['product_assistant_title'] : __('AI Product Assistant', 'ai-product-assistant');
$default_description = isset($options['product_assistant_description']) ? $options['product_assistant_description'] : __('Ask AI about this product', 'ai-product-assistant');
$default_placeholder = isset($options['product_assistant_placeholder']) ? $options['product_assistant_placeholder'] : __('e.g., Is this product suitable for beginners?', 'ai-product-assistant');
$default_button_text = isset($options['product_assistant_button_text']) ? $options['product_assistant_button_text'] : __('Ask AI', 'ai-product-assistant');
// Use shortcode parameters or default values
$title = !empty($atts['title']) ? $atts['title'] : $default_title;
$description = !empty($atts['description']) ? $atts['description'] : $default_description;
$placeholder = !empty($atts['placeholder']) ? $atts['placeholder'] : $default_placeholder;
$button_text = !empty($atts['button_text']) ? $atts['button_text'] : $default_button_text;
// Ensure scripts and styles are loaded
wp_enqueue_style('aipa-product-assistant-css', AIPA_PLUGIN_URL . 'assets/css/product-assistant.css', array('aipa-frontend-css'), AIPA_VERSION);
wp_enqueue_script('aipa-product-assistant-js', AIPA_PLUGIN_URL . 'assets/js/product-assistant.js', array('jquery'), AIPA_VERSION, true);
// Generate unique form ID
$unique_id = 'aipa-product-assistant-' . uniqid();
$form_id = $unique_id . '-form';
$input_id = $unique_id . '-input';
$button_id = $unique_id . '-button';
$error_id = $unique_id . '-error';
$loading_id = $unique_id . '-loading';
$results_id = $unique_id . '-results';
// Output form HTML
ob_start();
?>