You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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();
}

关键修复点说明

  1. 参数匹配修正:将save_deposit_breakdown方法的参数从3个改为2个,与woocommerce_checkout_create_order钩子的参数传递一致,确保方法能正确接收订单对象。
  2. 移除手动保存:删除$order->save()调用,避免干扰WooCommerce原生的订单保存流程,元数据会在钩子执行后由WooCommerce自动写入数据库。
  3. 修复启用判断逻辑:调整全局启用状态的判断条件,确保只有当插件开启时才执行预付款计算逻辑,避免session数据未正确初始化。
  4. session数据健壮性:无论是否有产品预付款,都初始化session中的预付款相关数据,避免后续保存方法因空值跳过写入。
  5. 调试日志优化:使用print_r将订单对象转为字符串输出,方便在服务器日志中查看详细信息,快速定位问题。

内容的提问来源于stack exchange,提问作者mikebension

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.11 15:35:55