$table_title, 'post_content' => $list_description, 'post_type' => AFFILILABS_CPT_COMPARISON_TABLE, 'post_status' => 'publish', 'meta_input' => array( AFFILILABS_META_KEY_COMPARISON_TABLE_PRODUCTS => $product_ids, AFFILILABS_META_KEY_LIST_CRITERIA_IDS => $criteria_ids, AFFILILABS_META_KEY_COMPARISON_TABLE_APPLIED_TEMPLATE_ID => $applied_template_id, AFFILILABS_META_KEY_COMPARISON_TABLE_TIER_BEST_PRICE => $tier_best_price, AFFILILABS_META_KEY_COMPARISON_TABLE_TIER_BEST_QUALITY => $tier_best_quality, AFFILILABS_META_KEY_COMPARISON_TABLE_TIER_BEST_COST_BENEFIT => $tier_best_cost_benefit, ), ); if ($table_id) { $comparison_table_post['ID'] = $table_id; $table_id = wp_update_post($comparison_table_post); } else { $table_id = wp_insert_post($comparison_table_post); } if (is_wp_error($table_id)) { throw new Exception('Error saving list: ' . esc_html($table_id->get_error_message())); } return $table_id; } public static function delete($table_id) { $table_id = intval($table_id); if (empty($table_id)) { throw new Exception('No List ID provided for deletion.'); } if (get_post_type($table_id) !== AFFILILABS_CPT_COMPARISON_TABLE) { throw new Exception('Invalid List ID provided for deletion.'); } $was_deleted = wp_delete_post($table_id, true); // Force delete if (!$was_deleted) { throw new Exception('There was an error deleting the list. Please try again.'); } return true; } public static function get_all() { $args = array( 'post_type' => AFFILILABS_CPT_COMPARISON_TABLE, 'posts_per_page' => -1, 'post_status' => 'any', ); $tables = get_posts($args); $formatted_tables = array(); foreach ($tables as $table) { try { $formatted_tables[] = self::get_table_data($table->ID); } catch (Exception $e) { AFFL_LoggerService::log("Failed to get data for List ID " . esc_html($table->ID) . ": " . esc_html($e->getMessage()), 'ERROR'); } } return $formatted_tables; } public static function get_table_data($table_id) { $table_id = intval($table_id); if ($table_id <= 1) { // 1 -> array throw new Exception('Invalid List ID provided.'); } $table_data = array( 'id' => $table_id, 'title' => '', 'list_description' => '', 'products' => [], 'criteria_ids' => [], 'linked_criteria_details' => [], 'applied_template_id' => null, 'tiers' => array( 'best_price' => null, 'best_quality' => null, 'best_cost_benefit' => null, ), ); $comparison_table_post = get_post($table_id); if (!$comparison_table_post || $comparison_table_post->post_type !== AFFILILABS_CPT_COMPARISON_TABLE) { throw new Exception('List not found or invalid list ID.'); } $table_data['title'] = $comparison_table_post->post_title; $table_data['list_description'] = $comparison_table_post->post_content; $table_data['applied_template_id'] = get_post_meta($table_id, AFFILILABS_META_KEY_COMPARISON_TABLE_APPLIED_TEMPLATE_ID, true); $criteria_ids = get_post_meta($table_id, AFFILILABS_META_KEY_LIST_CRITERIA_IDS, true); $table_data['criteria_ids'] = is_array($criteria_ids) ? $criteria_ids : []; $product_ids = get_post_meta($table_id, AFFILILABS_META_KEY_COMPARISON_TABLE_PRODUCTS, true); if (!empty($product_ids) && is_array($product_ids)) { if (class_exists('AFFLProductService')) { $table_data['products'] = AFFLProductService::get_products_by_ids($product_ids); } else { AFFL_LoggerService::log("AFFLProductService not available in AFFLComparisonTableService::get_table_data", 'ERROR'); } } if (!empty($table_data['criteria_ids'])) { if (class_exists('AFFLCriteriaService')) { $table_data['linked_criteria_details'] = AFFLCriteriaService::get_criteria_by_ids($table_data['criteria_ids']); } else { AFFL_LoggerService::log("AFFLCriteriaService not available in AFFLComparisonTableService::get_table_data", 'ERROR'); //@TODO: Handle error } } $table_data['tiers']['best_price'] = get_post_meta($table_id, AFFILILABS_META_KEY_COMPARISON_TABLE_TIER_BEST_PRICE, true); $table_data['tiers']['best_quality'] = get_post_meta($table_id, AFFILILABS_META_KEY_COMPARISON_TABLE_TIER_BEST_QUALITY, true); $table_data['tiers']['best_cost_benefit'] = get_post_meta($table_id, AFFILILABS_META_KEY_COMPARISON_TABLE_TIER_BEST_COST_BENEFIT, true); return $table_data; } public static function import_products_from_category($category_id) { $category_id = intval($category_id); if (empty($category_id)) { throw new Exception('No category ID provided for import.'); } $args = array( 'post_type' => AFFILILABS_CPT_PRODUCT, 'posts_per_page' => -1, 'post_status' => 'publish', 'fields' => 'ids', 'tax_query' => array( array( 'taxonomy' => AFFILILABS_TAXONOMY_PRODUCT_CATEGORY, 'field' => 'term_id', 'terms' => $category_id, ), ), ); $product_ids = get_posts($args); return $product_ids; } public static function import_products_from_tag($tag_id) { $tag_id = intval($tag_id); if (empty($tag_id)) { throw new Exception('No tag ID provided for import.'); } $args = array( 'post_type' => AFFILILABS_CPT_PRODUCT, 'posts_per_page' => -1, 'post_status' => 'publish', 'fields' => 'ids', 'tax_query' => array( array( 'taxonomy' => 'post_tag', 'field' => 'term_id', 'terms' => $tag_id, ), ), ); $product_ids = get_posts($args); return $product_ids; } /** * Suggests lists (comparison tables) based on existing products and lists using AI. * * @param array $data_for_ai Associative array containing data for the AI, e.g., 'all_products', 'all_lists'. * @return array An array of suggested lists. Returns empty array on failure or no suggestions. * @throws Exception If an error occurs during the API call or data processing. */ public static function suggest_lists(array $data_for_ai) { $ai_language = $data_for_ai['language'] ?? ''; if (empty($ai_language)) { AFFL_LoggerService::log('No language provided for AI list suggestion.', 'WARNING'); return ['status' => 'error', 'message' => 'AI language is missing.']; } $data = AFFL_AIService::request('ai/suggest_product_list', [ 'type' => 'suggest_list', 'data' => $data_for_ai, 'language' => $ai_language ]); $suggested_lists_json_string = $data['data'] ?? '[]'; $suggested_lists = json_decode($suggested_lists_json_string, true); if (json_last_error() !== JSON_ERROR_NONE) { AFFL_LoggerService::log('Failed to decode nested AI Suggest Lists JSON string. Error: ' . esc_html(json_last_error_msg()) . ". String: " . esc_html($suggested_lists_json_string), 'ERROR'); throw new Exception('Failed to decode nested AI Suggestion API response JSON: ' . esc_html(json_last_error_msg())); } // Propagate error/error_pro status directly from the AI service if (isset($data['status']) && $data['status'] !== 'ok') { return [ 'status' => $data['status'], 'message' => $data['message'] ?? __('Lists could not be suggested.', 'affililabs'), ]; } return ['status' => 'ok', 'lists_response' => $suggested_lists]; } }