WooCommerce预付款数据无法保存至数据库的问题排查求助
修复WooCommerce预付款订单元数据未保存问题
问题诊断
你的代码存在几个关键问题导致预付款数据无法写入订单元数据:
- 参数不匹配:
woocommerce_checkout_create_order钩子仅传递2个参数($order和$data),但save_deposit_breakdown方法声明了3个参数,导致方法执行异常。 - 不必要的手动保存:在
woocommerce_checkout_create_order钩子中手动调用$order->save()会干扰WooCommerce原生订单保存流程,可能导致元数据丢失。 - 全局启用判断逻辑错误:
if (!get_option('enable_advanced_payment', 'no') === 'yes')逻辑反转,导致插件启用状态判断失效,进而session数据未正确设置。 - 调试日志写法错误:直接输出
$order对象到error_log无法读取有效信息,不利于排查问题。
修复后的完整代码
<?php if (!defined('ABSPATH')) { exit; } if (!class_exists('Advance_Payment_Calculations')) { class Advance_Payment_Calculations { private static $instance = null; public static function get_instance() { if (null === self::$instance) { self::$instance = new self(); } return self::$instance; } public function init() { // Override the cart calculation to include product/category deposits add_action('woocommerce_cart_calculate_fees', array($this, 'calculate_deposits_in_cart'), 20, 1); // Store deposit breakdown in order meta add_action('woocommerce_checkout_create_order', array($this, 'save_deposit_breakdown'), 20, 2 ); } /** * Calculate deposits in cart considering product and category settings */ public function calculate_deposits_in_cart($cart) { if (is_admin() && !defined('DOING_AJAX')) { return; } // 修复全局启用判断逻辑 if (get_option('enable_advanced_payment', 'no') !== 'yes') { return; } $total_deposit = 0; $deposit_breakdown = array(); $has_product_deposit = false; foreach ($cart->get_cart() as $cart_item_key => $cart_item) { $product_id = $cart_item['product_id']; $variation_id = $cart_item['variation_id']; $quantity = $cart_item['quantity']; $line_total = $cart_item['line_total']; // Get deposit settings for this product $deposit_settings = Advance_Payment_Product::get_product_deposit_settings($product_id, $variation_id); if ($deposit_settings['enable']) { $has_product_deposit = true; // Calculate deposit for this line item if ($deposit_settings['type'] === 'percentage') { $item_deposit = $line_total * ($deposit_settings['value'] / 100); } else { $item_deposit = $deposit_settings['value'] * $quantity; } // Ensure deposit doesn't exceed line total $item_deposit = min($item_deposit, $line_total); $total_deposit += $item_deposit; // Store breakdown $product = wc_get_product($variation_id ?: $product_id); $deposit_breakdown[] = array( 'product_name' => $product->get_name(), 'quantity' => $quantity, 'line_total' => $line_total, 'deposit_amount' => $item_deposit, 'source' => $deposit_settings['source'], 'type' => $deposit_settings['type'], 'value' => $deposit_settings['value'] ); } } // 确保session数据始终被设置,避免后续读取空值 WC()->session->set('advance_payment_breakdown', $deposit_breakdown); WC()->session->set('advance_payment_total', $total_deposit); WC()->session->set('advance_payment_remaining', ($cart->cart_contents_total + $cart->shipping_total) - $total_deposit); // If no product-specific deposits, use global logic from original class if (!$has_product_deposit) { // Let the original class handle global deposit return; } // Add deposit as negative fee (reduces amount to pay) if ($total_deposit > 0) { $cart->add_fee(__('Advance Payment', 'advance-payment-wc'), -$total_deposit); } } // 修正参数数量,匹配钩子传递的参数 public function save_deposit_breakdown($order, $data) { if (!WC()->session) { return; } // 优化调试日志写法 error_log('Order object: ' . print_r($order, true)); $breakdown = WC()->session->get('advance_payment_breakdown'); $total_deposit = WC()->session->get('advance_payment_total'); $remaining_balance = WC()->session->get('advance_payment_remaining'); if (empty($breakdown) || !is_array($breakdown)) { return; } // Save order meta properly $order->update_meta_data('_advance_payment_breakdown', $breakdown); $order->update_meta_data('_advance_payment_total', $total_deposit); $order->update_meta_data('_advance_payment_remaining', $remaining_balance); $order->update_meta_data('_advance_payment_type', 'product_specific'); // 移除手动save调用,由WooCommerce自动处理保存 // $order->save(); // Clear session AFTER saving WC()->session->__unset('advance_payment_breakdown'); WC()->session->__unset('advance_payment_total'); WC()->session->__unset('advance_payment_remaining'); } /** * Get the deposit amount for a product */ public static function get_product_deposit_amount($product_id, $variation_id = 0) { $product = wc_get_product($variation_id ?: $product_id); if (!$product) { return 0; } $price = $product->get_price(); $deposit_settings = Advance_Payment_Product::get_product_deposit_settings($product_id, $variation_id); return Advance_Payment_Product::calculate_deposit_amount($price, $deposit_settings); } } // Initialize $advance_payment_calculations = Advance_Payment_Calculations::get_instance(); $advance_payment_calculations->init(); }
关键修复点说明
- 参数匹配修正:将
save_deposit_breakdown方法的参数从3个改为2个,与woocommerce_checkout_create_order钩子的参数传递一致,确保方法能正确接收订单对象。 - 移除手动保存:删除
$order->save()调用,避免干扰WooCommerce原生的订单保存流程,元数据会在钩子执行后由WooCommerce自动写入数据库。 - 修复启用判断逻辑:调整全局启用状态的判断条件,确保只有当插件开启时才执行预付款计算逻辑,避免session数据未正确初始化。
- session数据健壮性:无论是否有产品预付款,都初始化session中的预付款相关数据,避免后续保存方法因空值跳过写入。
- 调试日志优化:使用
print_r将订单对象转为字符串输出,方便在服务器日志中查看详细信息,快速定位问题。
内容的提问来源于stack exchange,提问作者mikebension
相关产品推荐
相关产品推荐

