/** * mingkos Customization System - Enhanced AJAX Handlers (Merged & Fixed) * 印刷产品定制系统 - 增强版AJAX处理函数(合并修复版) * * @version 5.3.1 - 移除重复代码,优化函数定义 * @package mingkos */ // =============================== // 🛡️ SECURITY CHECK // =============================== if (!defined('ABSPATH')) { exit; } // Prevent duplicate loading if (defined('mingkos_AJAX_ENHANCED_LOADED')) { return; } define('mingkos_AJAX_ENHANCED_LOADED', true); // =============================== // 📝 确保日志函数存在 // =============================== if (!function_exists('mingkos_log')) { function mingkos_log($message, $data = []) { if (defined('WP_DEBUG') && WP_DEBUG) { $log_entry = '[' . current_time('mysql') . '] mingkos: ' . $message; if (!empty($data)) { $log_entry .= ' | Data: ' . json_encode($data, JSON_UNESCAPED_UNICODE); } error_log($log_entry); } } } // =============================== // 🚀 ENHANCED AJAX HANDLERS // =============================== /** * Enhanced AJAX handler for adding customized product to cart * 增强版AJAX处理函数:添加定制产品到购物车 */ if (!function_exists('mingkos_enhanced_add_to_cart_ajax')) { add_action('wp_ajax_mingkos_enhanced_add_to_cart', 'mingkos_enhanced_add_to_cart_ajax'); add_action('wp_ajax_nopriv_mingkos_enhanced_add_to_cart', 'mingkos_enhanced_add_to_cart_ajax'); function mingkos_enhanced_add_to_cart_ajax() { // Start output buffering ob_start(); // Log start of request mingkos_log('=== Enhanced AJAX Add to Cart Start ===', [ 'time' => current_time('mysql'), 'method' => $_SERVER['REQUEST_METHOD'], 'content_type' => $_SERVER['CONTENT_TYPE'] ?? 'N/A' ]); // === 调试1:记录原始 POST 数据 === if (defined('WP_DEBUG') && WP_DEBUG) { error_log('=== [AJAX] Raw POST ==='); error_log(print_r($_POST, true)); error_log('=== End Raw POST ==='); } try { // Check WooCommerce if (!class_exists('WooCommerce')) { throw new Exception('WooCommerce not active'); } // Verify nonce $nonce = sanitize_text_field($_POST['mingkos_nonce'] ?? ($_POST['nonce'] ?? '')); if (!wp_verify_nonce($nonce, 'mingkos_add_to_cart')) { throw new Exception('Security check failed. Please refresh the page and try again.'); } // Get and validate product ID $product_id = intval($_POST['mingkos_product_id'] ?? ($_POST['product_id'] ?? 0)); if ($product_id <= 0) { throw new Exception('Invalid product ID'); } $product = wc_get_product($product_id); if (!$product || !$product->is_purchasable()) { throw new Exception('Product not found or not purchasable'); } // Check if customization is enabled if (function_exists('mingkos_is_customizable') && !mingkos_is_customizable($product_id)) { throw new Exception('Customization is not enabled for this product'); } // Get configuration from POST data $configuration = mingkos_sanitize_ajax_configuration($_POST); if (defined('WP_DEBUG') && WP_DEBUG) { error_log('=== [AJAX] Parsed Configuration ==='); error_log(print_r($configuration, true)); error_log('=== End Parsed Configuration ==='); } // Log configuration mingkos_log('Configuration received', [ 'product_id' => $product_id, 'order_type' => $configuration['order_type'], 'quantity' => $configuration['quantity'], 'attributes_count' => count($configuration['attributes'] ?? []), 'printing_count' => count($configuration['printing_options'] ?? []), 'packaging_count' => count($configuration['packaging_options'] ?? []), 'dynamic_count' => count($configuration['dynamic_parameters'] ?? []), 'calculator_area' => $configuration['calculator_costs']['area'] ?? 0, 'calculator_volume' => $configuration['calculator_costs']['volume'] ?? 0 ]); // Validate configuration $validation = mingkos_validate_enhanced_configuration($product_id, $configuration); if (!$validation['valid']) { throw new Exception(implode(', ', $validation['errors'])); } // Calculate price using enhanced engine or fallback if (function_exists('mingkos_calculate_product_price_complete')) { $price_calculation = mingkos_calculate_product_price_complete($product_id, $configuration); } else if (function_exists('mingkos_calculate_product_price')) { $price_calculation = mingkos_calculate_product_price($product_id, $configuration); } else { // Fallback to basic price calculation $base_price = $product->get_price(); $quantity = $configuration['quantity']; $price_calculation = [ 'success' => true, 'total' => $base_price * $quantity, 'price_per_unit' => $base_price, 'subtotal' => $base_price * $quantity, 'base_price' => $base_price, 'currency' => get_woocommerce_currency() ]; } if (!$price_calculation['success']) { throw new Exception($price_calculation['error'] ?? 'Price calculation failed'); } // Handle file uploads $design_files = []; if (function_exists('mingkos_process_design_files')) { $design_files = mingkos_process_design_files($product_id, $_FILES); } else if (!empty($_FILES['design_files'])) { // Fallback file processing $design_files = mingkos_process_design_files_fallback($_FILES); } // Add configuration to cart item data $cart_item_data = [ 'mingkos_customization' => true, 'mingkos_config' => $configuration, 'mingkos_price_data' => $price_calculation, 'mingkos_hash' => mingkos_generate_config_hash($configuration), 'mingkos_timestamp' => current_time('timestamp'), 'mingkos_version' => '5.3.1' ]; // Add design files if uploaded if (!empty($design_files)) { $cart_item_data['mingkos_design_files'] = $design_files; $configuration['design_files'] = $design_files; } // Generate customization summary $current_lang = function_exists('mingkos_get_user_language') ? mingkos_get_user_language() : 'en_US'; if (function_exists('mingkos_generate_config_summary_updated')) { $summary = mingkos_generate_config_summary_updated($product_id, $configuration, $current_lang); } else if (function_exists('mingkos_generate_config_summary')) { $summary = mingkos_generate_config_summary($product_id, $configuration); } else { $summary = sprintf(__('Customized: %s', 'mingkos'), $product->get_name()); } $cart_item_data['mingkos_summary'] = $summary; // 记录即将存入购物车的数据 if (defined('WP_DEBUG') && WP_DEBUG) { error_log('=== [AJAX] Cart Item Data ==='); error_log(print_r($cart_item_data, true)); error_log('=== End Cart Item Data ==='); } // Add to cart $variation_id = $configuration['variation_id'] ?? 0; $cart_item_key = WC()->cart->add_to_cart( $product_id, $configuration['quantity'], $variation_id, [], // Variation attributes $cart_item_data ); if (!$cart_item_key) { throw new Exception('Failed to add product to cart'); } // Calculate cart totals WC()->cart->calculate_totals(); // Get updated cart fragments $cart_fragments = mingkos_get_enhanced_cart_fragments(); // Generate success response $response = [ 'success' => true, 'message' => __('Product added to cart successfully!', 'mingkos'), 'cart_item_key' => $cart_item_key, 'cart_item_data' => [ 'product_name' => $product->get_name(), 'quantity' => $configuration['quantity'], 'custom_price' => $price_calculation['price_per_unit'], 'total_price' => $price_calculation['total'] ], 'cart_fragments' => $cart_fragments, 'redirect_url' => wc_get_cart_url(), 'price_summary' => [ 'unit_price' => wc_price($price_calculation['price_per_unit']), 'total_price' => wc_price($price_calculation['total']), 'quantity' => $configuration['quantity'], 'breakdown' => $price_calculation['breakdown'] ?? [] ], 'configuration_summary' => $summary, 'customization_hash' => $cart_item_data['mingkos_hash'] ]; // Log success mingkos_log('Add to cart successful', [ 'cart_item_key' => $cart_item_key, 'total_price' => $price_calculation['total'], 'cart_count' => WC()->cart->get_cart_contents_count() ]); wp_send_json_success($response); } catch (Exception $e) { // Log error mingkos_log('Add to cart error', [ 'error' => $e->getMessage(), 'trace' => $e->getTraceAsString() ]); wp_send_json_error([ 'success' => false, 'message' => $e->getMessage(), 'code' => 'mingkos_ERROR' ]); } // End output buffering and send response ob_end_clean(); } } /** * Sanitize AJAX configuration data (Enhanced) * 清理AJAX配置数据(增强版) */ if (!function_exists('mingkos_sanitize_ajax_configuration')) { function mingkos_sanitize_ajax_configuration($post_data) { $config = [ 'order_type' => 'normal', 'quantity' => 1, 'attributes' => [], 'printing_options' => [], 'packaging_options' => [], 'packaging_type' => 'standard', 'dynamic_parameters' => [], 'calculator_costs' => ['area' => 0, 'volume' => 0], 'calculator_inputs' => [], 'order_note' => '', 'design_files' => [], 'variation_id' => 0 ]; // 订单类型 if (isset($post_data['order_type'])) { $config['order_type'] = in_array($post_data['order_type'], ['normal', 'sample']) ? sanitize_text_field($post_data['order_type']) : 'normal'; } // 数量 if (isset($post_data['order_quantity'])) { $config['quantity'] = max(1, intval($post_data['order_quantity'])); } elseif (isset($post_data['quantity'])) { $config['quantity'] = max(1, intval($post_data['quantity'])); } // 属性:尝试解析 JSON 或直接使用数组 if (isset($post_data['attributes'])) { $attributes = $post_data['attributes']; if (is_string($attributes)) { $attributes = json_decode(stripslashes($attributes), true); } if (is_array($attributes)) { $config['attributes'] = $attributes; } } // 印刷选项 if (isset($post_data['printing_options'])) { $printing = $post_data['printing_options']; if (is_string($printing)) { $printing = json_decode(stripslashes($printing), true); } if (is_array($printing)) { $config['printing_options'] = $printing; } } // 包装选项 if (isset($post_data['packaging_options'])) { $packaging = $post_data['packaging_options']; if (is_string($packaging)) { $packaging = json_decode(stripslashes($packaging), true); } if (is_array($packaging)) { $config['packaging_options'] = $packaging; } } // 包装类型 if (isset($post_data['packaging_type'])) { $config['packaging_type'] = sanitize_text_field($post_data['packaging_type']); } // 动态参数 if (isset($post_data['dynamic_parameters'])) { $dynamic = $post_data['dynamic_parameters']; if (is_string($dynamic)) { $dynamic = json_decode(stripslashes($dynamic), true); } if (is_array($dynamic)) { $config['dynamic_parameters'] = $dynamic; } } // 计算器成本 if (isset($post_data['calculator_area'])) { $config['calculator_costs']['area'] = max(0, floatval($post_data['calculator_area'])); } if (isset($post_data['calculator_volume'])) { $config['calculator_costs']['volume'] = max(0, floatval($post_data['calculator_volume'])); } // ========== 修复:收集计算器输入值(只定义一次) ========== $config['calculator_inputs'] = mingkos_collect_calculator_inputs($post_data); // 订单备注 if (isset($post_data['order_note'])) { $config['order_note'] = sanitize_textarea_field($post_data['order_note']); } // 变体ID if (isset($post_data['variation_id'])) { $config['variation_id'] = intval($post_data['variation_id']); } return apply_filters('mingkos_sanitized_configuration', $config); } } /** * 收集计算器输入值(独立函数,避免重复代码) */ if (!function_exists('mingkos_collect_calculator_inputs')) { function mingkos_collect_calculator_inputs($post_data) { $inputs = []; // 面积计算器输入 if (isset($post_data['calculator_area_input']) && is_array($post_data['calculator_area_input'])) { $inputs['area'] = [ 'length' => floatval($post_data['calculator_area_input']['length'] ?? 0), 'width' => floatval($post_data['calculator_area_input']['width'] ?? 0), 'length_unit' => sanitize_text_field($post_data['calculator_area_input']['length_unit'] ?? 'm'), 'width_unit' => sanitize_text_field($post_data['calculator_area_input']['width_unit'] ?? 'm'), ]; } elseif (isset($post_data['area_length']) && isset($post_data['area_width'])) { // 兼容旧格式 $inputs['area'] = [ 'length' => floatval($post_data['area_length'] ?? 0), 'width' => floatval($post_data['area_width'] ?? 0), 'length_unit' => sanitize_text_field($post_data['area_length_unit'] ?? 'm'), 'width_unit' => sanitize_text_field($post_data['area_width_unit'] ?? 'm'), ]; } // 体积计算器输入 if (isset($post_data['calculator_volume_input']) && is_array($post_data['calculator_volume_input'])) { $inputs['volume'] = [ 'length' => floatval($post_data['calculator_volume_input']['length'] ?? 0), 'width' => floatval($post_data['calculator_volume_input']['width'] ?? 0), 'height' => floatval($post_data['calculator_volume_input']['height'] ?? 0), 'unit' => sanitize_text_field($post_data['calculator_volume_input']['unit'] ?? 'm'), ]; } elseif (isset($post_data['volume_length']) && isset($post_data['volume_width']) && isset($post_data['volume_height'])) { // 兼容旧格式 $inputs['volume'] = [ 'length' => floatval($post_data['volume_length'] ?? 0), 'width' => floatval($post_data['volume_width'] ?? 0), 'height' => floatval($post_data['volume_height'] ?? 0), 'unit' => sanitize_text_field($post_data['volume_unit'] ?? 'm'), ]; } return $inputs; } } // =============================== // 🛠️ VALIDATION FUNCTIONS // =============================== /** * Validate enhanced configuration * 验证增强版配置 */ if (!function_exists('mingkos_validate_enhanced_configuration')) { function mingkos_validate_enhanced_configuration($product_id, $config) { $errors = []; // Get product data if (function_exists('mingkos_get_product_data_enhanced')) { $product_data = mingkos_get_product_data_enhanced($product_id); } elseif (function_exists('mingkos_get_product_data')) { $product_data = mingkos_get_product_data($product_id); } else { $product_data = ['enabled' => true]; } if (!$product_data || !$product_data['enabled']) { $errors[] = 'Product customization is not enabled'; return ['valid' => false, 'errors' => $errors]; } // Validate order type $allowed_order_types = ['normal']; if (isset($product_data['sample_enabled']) && $product_data['sample_enabled']) { $allowed_order_types[] = 'sample'; } if (!in_array($config['order_type'], $allowed_order_types)) { $errors[] = 'Invalid order type'; } // Validate quantity based on order type $quantity = intval($config['quantity']); if ($config['order_type'] === 'sample') { // Sample order validation if (!isset($product_data['sample_enabled']) || !$product_data['sample_enabled']) { $errors[] = 'Sample ordering is not enabled for this product'; } if ($quantity < 1) { $errors[] = 'Sample order minimum quantity is 1'; } $sample_max_qty = intval($product_data['sample_max_qty'] ?? 5); if ($quantity > $sample_max_qty) { $errors[] = "Sample order maximum quantity is {$sample_max_qty}"; } } else { // Normal order validation $min_quantity = intval($product_data['min_quantity'] ?? 1); if ($quantity < $min_quantity) { $errors[] = "Minimum order quantity is {$min_quantity}"; } $max_quantity = intval($product_data['maximum_order_quantity'] ?? 10000); if ($quantity > $max_quantity) { $errors[] = "Maximum order quantity is {$max_quantity}"; } } // Validate required attributes if (!empty($product_data['attributes'])) { foreach ($product_data['attributes'] as $index => $attribute) { if (isset($attribute['required']) && $attribute['required']) { $has_selection = false; if (isset($config['attributes'][$index])) { $selected = $config['attributes'][$index]; if (is_array($selected)) { $has_selection = !empty($selected); } else { $has_selection = $selected !== '' && $selected !== null; } } if (!$has_selection) { $errors[] = "Required attribute missing: {$attribute['name']}"; } } } } // Validate calculator costs if (isset($config['calculator_costs'])) { if (!is_numeric($config['calculator_costs']['area'] ?? 0)) { $errors[] = 'Invalid area calculator cost'; } if (!is_numeric($config['calculator_costs']['volume'] ?? 0)) { $errors[] = 'Invalid volume calculator cost'; } } return [ 'valid' => empty($errors), 'errors' => $errors, 'sanitized_config' => $config ]; } } // =============================== // 📁 FILE UPLOAD FUNCTIONS // =============================== /** * Process design files upload (Enhanced) * 处理设计文件上传(增强版) */ if (!function_exists('mingkos_process_design_files')) { function mingkos_process_design_files($product_id, $files) { $uploaded_files = []; if (empty($files) || !isset($files['design_files'])) { return $uploaded_files; } // Check if file upload is enabled for this product if (function_exists('mingkos_get_product_data_enhanced')) { $product_data = mingkos_get_product_data_enhanced($product_id); if (!$product_data['file_upload_enabled']) { return $uploaded_files; } $max_size = $product_data['max_file_size'] * 1024 * 1024; } else { $max_size = 100 * 1024 * 1024; // Default 100MB } $allowed_types = ['pdf', 'ai', 'psd', 'jpg', 'jpeg', 'png', 'zip', 'eps', 'cdr', 'svg']; // Process each file if (is_array($files['design_files']['name'])) { $file_count = count($files['design_files']['name']); for ($i = 0; $i < $file_count; $i++) { if ($files['design_files']['error'][$i] !== UPLOAD_ERR_OK) { continue; } $file = [ 'name' => $files['design_files']['name'][$i], 'type' => $files['design_files']['type'][$i], 'tmp_name' => $files['design_files']['tmp_name'][$i], 'error' => $files['design_files']['error'][$i], 'size' => $files['design_files']['size'][$i] ]; $file_result = mingkos_process_single_design_file($file, $max_size, $allowed_types); if ($file_result) { $uploaded_files[] = $file_result; } } } else { if ($files['design_files']['error'] === UPLOAD_ERR_OK) { $file_result = mingkos_process_single_design_file($files['design_files'], $max_size, $allowed_types); if ($file_result) { $uploaded_files[] = $file_result; } } } return $uploaded_files; } } /** * Process single design file * 处理单个设计文件 */ if (!function_exists('mingkos_process_single_design_file')) { function mingkos_process_single_design_file($file, $max_size, $allowed_types) { // Check for upload errors if ($file['error'] !== UPLOAD_ERR_OK) { mingkos_log('File upload error', [ 'file' => $file['name'], 'error' => $file['error'], ]); return false; } // Check file size if ($file['size'] > $max_size) { mingkos_log('File too large', [ 'file' => $file['name'], 'size' => $file['size'], 'max_size' => $max_size ]); return false; } // Check file type $file_extension = strtolower(pathinfo($file['name'], PATHINFO_EXTENSION)); if (!in_array($file_extension, $allowed_types)) { mingkos_log('Invalid file type', [ 'file' => $file['name'], 'type' => $file_extension, 'allowed' => $allowed_types ]); return false; } // Upload file to WordPress media library require_once(ABSPATH . 'wp-admin/includes/file.php'); require_once(ABSPATH . 'wp-admin/includes/media.php'); require_once(ABSPATH . 'wp-admin/includes/image.php'); $upload = wp_handle_upload($file, ['test_form' => false]); if (!isset($upload['error'])) { $attachment = [ 'post_mime_type' => $file['type'], 'post_title' => preg_replace('/\.[^.]+$/', '', basename($file['name'])), 'post_content' => '', 'post_status' => 'inherit', 'guid' => $upload['url'] ]; $attachment_id = wp_insert_attachment($attachment, $upload['file']); if (!is_wp_error($attachment_id)) { $attachment_data = wp_generate_attachment_metadata($attachment_id, $upload['file']); wp_update_attachment_metadata($attachment_id, $attachment_data); mingkos_log('File uploaded successfully', [ 'file' => $file['name'], 'attachment_id' => $attachment_id, 'url' => $upload['url'] ]); return [ 'id' => $attachment_id, 'name' => $file['name'], 'url' => $upload['url'], 'size' => $file['size'], 'type' => $file['type'] ]; } } return false; } } /** * Fallback design file processing * 备用设计文件处理 */ if (!function_exists('mingkos_process_design_files_fallback')) { function mingkos_process_design_files_fallback($files) { $uploaded_files = []; if (empty($files) || !isset($files['design_files'])) { return $uploaded_files; } require_once(ABSPATH . 'wp-admin/includes/file.php'); if (is_array($files['design_files']['name'])) { foreach ($files['design_files']['name'] as $key => $value) { if ($files['design_files']['name'][$key] && $files['design_files']['error'][$key] === UPLOAD_ERR_OK) { $file = [ 'name' => $files['design_files']['name'][$key], 'type' => $files['design_files']['type'][$key], 'tmp_name' => $files['design_files']['tmp_name'][$key], 'error' => $files['design_files']['error'][$key], 'size' => $files['design_files']['size'][$key] ]; $upload = wp_handle_upload($file, ['test_form' => false]); if (!isset($upload['error'])) { $uploaded_files[] = [ 'url' => $upload['url'], 'name' => $file['name'] ]; } } } } else { if ($files['design_files']['name'] && $files['design_files']['error'] === UPLOAD_ERR_OK) { $upload = wp_handle_upload($files['design_files'], ['test_form' => false]); if (!isset($upload['error'])) { $uploaded_files[] = [ 'url' => $upload['url'], 'name' => $files['design_files']['name'] ]; } } } return $uploaded_files; } } // =============================== // 🔧 UTILITY FUNCTIONS // =============================== /** * Generate configuration hash * 生成配置哈希值 */ if (!function_exists('mingkos_generate_config_hash')) { function mingkos_generate_config_hash($config) { $hash_data = [ 'order_type' => $config['order_type'] ?? 'normal', 'quantity' => $config['quantity'] ?? 1, 'attributes' => $config['attributes'] ?? [], 'printing_options' => $config['printing_options'] ?? [], 'packaging_options' => $config['packaging_options'] ?? [], 'packaging_type' => $config['packaging_type'] ?? 'standard', 'dynamic_parameters' => $config['dynamic_parameters'] ?? [], 'calculator_costs' => $config['calculator_costs'] ?? ['area' => 0, 'volume' => 0] ]; return md5(serialize($hash_data)); } } /** * Get enhanced cart fragments * 获取增强版购物车片段 */ if (!function_exists('mingkos_get_enhanced_cart_fragments')) { function mingkos_get_enhanced_cart_fragments() { if (!class_exists('WooCommerce') || !WC()->cart) { return []; } $fragments = []; // Cart count $fragments['span.mingkos-cart-count'] = '' . WC()->cart->get_cart_contents_count() . ''; // Cart total $fragments['span.mingkos-cart-total'] = '' . WC()->cart->get_cart_total() . ''; // Mini cart widget if (function_exists('woocommerce_mini_cart')) { ob_start(); woocommerce_mini_cart(); $fragments['div.widget_shopping_cart_content'] = '
'; } return apply_filters('mingkos_cart_fragments', $fragments); } } // =============================== // 💰 PRICE CALCULATION AJAX (UNIFIED) // =============================== /** * AJAX handler for price calculation (UNIFIED VERSION) * AJAX价格计算处理程序(统一版本) */ if (!function_exists('mingkos_ajax_calculate_price')) { add_action('wp_ajax_mingkos_calculate_price', 'mingkos_ajax_calculate_price'); add_action('wp_ajax_nopriv_mingkos_calculate_price', 'mingkos_ajax_calculate_price'); function mingkos_ajax_calculate_price() { try { // Verify nonce $nonce = sanitize_text_field($_POST['nonce'] ?? ''); if (!wp_verify_nonce($nonce, 'mingkos_price_calc')) { throw new Exception('Security check failed'); } $product_id = intval($_POST['product_id'] ?? 0); if (!$product_id) { throw new Exception('Product ID is required'); } // Get configuration $config = mingkos_sanitize_ajax_configuration($_POST); // Calculate price if (function_exists('mingkos_calculate_product_price_complete')) { $calculation = mingkos_calculate_product_price_complete($product_id, $config); } else if (function_exists('mingkos_calculate_product_price')) { $calculation = mingkos_calculate_product_price($product_id, $config); } else { // Fallback calculation $product = wc_get_product($product_id); if (!$product) { throw new Exception('Product not found'); } $base_price = $product->get_price(); $quantity = $config['quantity']; $total = $base_price * $quantity; $calculation = [ 'success' => true, 'price_per_unit' => $base_price, 'total' => $total, 'subtotal' => $total, 'base_price' => $base_price, 'currency' => get_woocommerce_currency() ]; } if (!$calculation['success']) { throw new Exception($calculation['error'] ?? 'Price calculation failed'); } // Format response $response = [ 'success' => true, 'data' => [ 'product_id' => $product_id, 'quantity' => $config['quantity'], 'order_type' => $config['order_type'], 'base_price' => $calculation['base_price'] ?? 0, 'attribute_adjustments' => $calculation['attribute_adjustments'] ?? 0, 'printing_costs' => $calculation['printing_costs'] ?? 0, 'packaging_costs' => $calculation['packaging_costs'] ?? 0, 'dynamic_param_adjustments' => $calculation['dynamic_param_adjustments'] ?? 0, 'calculator_costs' => $calculation['calculator_costs'] ?? 0, 'sample_discount' => $calculation['sample_discount'] ?? 0, 'quantity_discount' => $calculation['quantity_discount'] ?? 0, 'subtotal' => $calculation['subtotal'] ?? 0, 'total' => $calculation['total'] ?? 0, 'price_per_unit' => $calculation['price_per_unit'] ?? 0, 'currency' => get_woocommerce_currency(), 'currency_symbol' => get_woocommerce_currency_symbol(), 'breakdown' => $calculation['breakdown'] ?? [], 'formatted_total' => wc_price($calculation['total']), 'formatted_unit_price' => wc_price($calculation['price_per_unit']), 'formatted_breakdown' => [] ] ]; // Format breakdown items if (!empty($calculation['breakdown'])) { foreach ($calculation['breakdown'] as $item) { $response['data']['formatted_breakdown'][] = [ 'label' => $item['label'] ?? '', 'value' => $item['value'] ?? 0, 'formatted' => ($item['value'] < 0 ? '-' : '+') . wc_price(abs($item['value'])), 'type' => $item['type'] ?? '', 'per_unit' => $item['per_unit'] ?? false ]; } } // Prepare breakdown HTML $breakdown_html = ''; if (!empty($calculation['breakdown'])) { $breakdown_html .= 'mingkos requires WooCommerce to be installed and activated.
| ' . __('💰 单价', 'mingkos') . ' | '; echo '' . wc_price($unit_price) . ' | '; echo '
|---|---|
| ' . __('📦 总价', 'mingkos') . ' | '; echo '' . wc_price($total_price) . ' | '; echo '
| ' . __('🔢 数量', 'mingkos') . ' | '; echo '' . $quantity . __(' 件', 'mingkos') . ' | '; echo '
| ' . __('📋 订单类型', 'mingkos') . ' | '; echo '' . esc_html($order_type_label) . ' | '; echo '
| ' . __('💵 基础价格', 'mingkos') . ' | '; echo '' . wc_price($base_price) . __(' /件', 'mingkos') . ' | '; echo '
| ' . __('🏷️ 产品属性', 'mingkos') . ' | '; echo '';
if (!empty($config['attributes']) && is_array($config['attributes'])) {
$attributes = $config['attributes'];
$has_display = false;
// 检查是索引数组还是关联数组
$is_indexed = array_keys($attributes) === range(0, count($attributes)-1);
if ($is_indexed) {
foreach ($attributes as $attr_index => $selected_value) {
$attr_name = '属性 #' . ($attr_index + 1);
$display_value = '';
if ($product_data && isset($product_data['attributes'][$attr_index])) {
$attr_data = $product_data['attributes'][$attr_index];
$attr_name = isset($attr_data['name']) ? $attr_data['name'] : $attr_name;
if (is_array($selected_value)) {
$labels = [];
foreach ($selected_value as $val) {
if (is_numeric($val) && isset($attr_data['options'][$val])) {
$labels[] = $attr_data['options'][$val]['label'] ?? $val;
} else {
$labels[] = $val;
}
}
$display_value = implode(', ', $labels);
} else {
if (is_numeric($selected_value) && isset($attr_data['options'][$selected_value])) {
$display_value = $attr_data['options'][$selected_value]['label'] ?? $selected_value;
} else {
$display_value = $selected_value;
}
}
} else {
$display_value = is_array($selected_value) ? implode(', ', $selected_value) : $selected_value;
}
if (!empty($display_value)) {
echo ' ' . esc_html($attr_name) . ': ' . esc_html($display_value) . ' ';
$has_display = true;
}
}
} else {
foreach ($attributes as $key => $value) {
$display = is_array($value) ? implode(', ', $value) : $value;
echo '' . esc_html($key) . ': ' . esc_html($display) . ' ';
$has_display = true;
}
}
if (!$has_display) {
echo '' . __('无属性选择', 'mingkos') . '';
}
} else {
echo '' . __('无属性选择', 'mingkos') . '';
}
echo ' | ';
echo '
| ' . __('🖨️ 印刷工艺', 'mingkos') . ' | '; echo '';
if (!empty($config['printing_options']) && is_array($config['printing_options'])) {
$printing_labels = [];
foreach ($config['printing_options'] as $value) {
$found = false;
if ($product_data && isset($product_data['printing_options']) && is_array($product_data['printing_options'])) {
foreach ($product_data['printing_options'] as $po) {
if (isset($po['key']) && $po['key'] == $value) {
$printing_labels[] = isset($po['label']) ? $po['label'] : $value;
$found = true;
break;
}
}
}
if (!$found) {
$printing_labels[] = $value;
}
}
echo implode(' ', array_map('esc_html', $printing_labels)); } else { echo '' . __('未选择印刷工艺', 'mingkos') . ''; } echo ' | ';
echo '
| ' . __('📦 包装选项', 'mingkos') . ' | '; echo '';
if (!empty($config['packaging_options']) && is_array($config['packaging_options'])) {
$packaging_labels = [];
foreach ($config['packaging_options'] as $value) {
$found = false;
if ($product_data && isset($product_data['packaging_options']) && is_array($product_data['packaging_options'])) {
foreach ($product_data['packaging_options'] as $po) {
if (isset($po['key']) && $po['key'] == $value) {
$packaging_labels[] = isset($po['label']) ? $po['label'] : $value;
$found = true;
break;
}
}
}
if (!$found) {
$packaging_labels[] = $value;
}
}
echo implode(' ', array_map('esc_html', $packaging_labels)); } else { echo '' . __('未选择包装选项', 'mingkos') . ''; } echo ' | ';
echo '
| ' . __('📦 包装类型', 'mingkos') . ' | '; echo '' . esc_html($packaging_type_label) . ' | '; echo '
| ' . __('⚙️ 动态参数', 'mingkos') . ' | '; echo '';
foreach ($config['dynamic_parameters'] as $key => $value) {
$display_value = is_array($value) ? implode(', ', $value) : $value;
echo ' ' . esc_html($key) . ': ' . esc_html($display_value) . ' ';
}
echo ' | ';
echo '
| ' . __('🧮 计算器成本', 'mingkos') . ' | '; echo ''; if ($has_calculator) { echo $calculator_html; } else { echo '' . __('未使用计算器', 'mingkos') . ''; } echo ' | '; echo '
| ' . __('📏 计算器输入', 'mingkos') . ' | '; echo '';
if (!empty($inputs['area']) && is_array($inputs['area'])) {
$a = $inputs['area'];
echo __('面积', 'mingkos') . ': ' . esc_html($a['length'] ?? 0) . ' ' . esc_html($a['length_unit'] ?? 'm')
. ' × ' . esc_html($a['width'] ?? 0) . ' ' . esc_html($a['width_unit'] ?? 'm') . ' '; } if (!empty($inputs['volume']) && is_array($inputs['volume'])) { $v = $inputs['volume']; echo __('体积', 'mingkos') . ': ' . esc_html($v['length'] ?? 0) . ' × ' . esc_html($v['width'] ?? 0) . ' × ' . esc_html($v['height'] ?? 0) . ' ' . esc_html($v['unit'] ?? 'm') . ' '; } echo ' | ';
echo '
| ' . __('📝 订单备注', 'mingkos') . ' | '; echo '' . nl2br(esc_html($config['order_note'])) . ' | '; echo '
| ' . __('📎 设计文件', 'mingkos') . ' | '; echo '';
if (!empty($design_files) && is_array($design_files) && $order) {
$order_id = $order->get_id();
foreach ($design_files as $index => $file) {
if (!is_array($file)) {
continue;
}
$file_name = isset($file['name']) ? $file['name'] : (isset($file['original_name']) ? $file['original_name'] : '文件_' . $index);
$download_url = admin_url('admin-ajax.php?action=mingkos_download_file&order_id=' . $order_id . '&file_id=' . $index);
echo ' ';
echo '📥 ' . esc_html($file_name) . '';
echo ' ';
}
} else {
echo '' . __('未上传设计文件', 'mingkos') . '';
}
echo ' | ';
echo '
| ' . __('费用项', 'mingkos') . ' | '; echo '' . __('金额', 'mingkos') . ' | '; echo '
|---|---|
| ' . esc_html($label) . ' | '; echo '' . $sign . ' ' . $formatted . ' | '; echo '
| ' . __('合计', 'mingkos') . ' | '; echo '' . wc_price($price_data['total']) . ' | '; echo '