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

WooCommerce添加额外库存位置:变体产品库存显示异常求助

WooCommerce双仓库库存显示问题(变体产品修复)

问题说明

在WooCommerce中为产品添加自定义库存字段,实现两个仓库库存总和在产品页面显示。简单产品的代码功能完全正常,但变体产品存在问题:后台已成功添加额外库存字段,但产品页面仅显示标准库存,未计算第二个仓库的库存。

简单产品可用代码

// 添加第二个库存字段(简单产品)
add_action( 'woocommerce_product_options_stock', 'bbloomer_additional_stock_location_for_simple_products' );

function bbloomer_additional_stock_location_for_simple_products() {
    global $product_object;
    if ($product_object->get_type() === 'simple') {
        echo '<div class="show_if_simple">';
        woocommerce_wp_text_input(
            array(
                'id' => '_stock2',
                'value' => get_post_meta( $product_object->get_id(), '_stock2', true ),
                'label' => '第二个仓库库存',
                'data_type' => 'stock',
            )
        );
        echo '</div>';
    }
}

// 保存简单产品的第二个库存
add_action( 'save_post_product', 'bbloomer_save_additional_stock_for_simple_products' );

function bbloomer_save_additional_stock_for_simple_products( $product_id ) {
    $product = wc_get_product( $product_id );
    if ( $product && $product->get_type() === 'simple' ) {
        if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) return;
        if ( isset( $_POST['_stock2'] ) ) {
            update_post_meta( $product_id, '_stock2', sanitize_text_field( $_POST['_stock2'] ) );
        }
    }
}

// 计算简单产品总库存
add_filter( 'woocommerce_product_get_stock_quantity' , 'bbloomer_get_overall_stock_quantity', 9999, 2 );

function bbloomer_get_overall_stock_quantity( $value, $product ) {
    if ($product->get_type() === 'simple') {
        $value = (int) $value + (int) get_post_meta( $product->get_id(), '_stock2', true );
    }
    return $value;
}

// 更新简单产品库存状态
add_filter( 'woocommerce_product_get_stock_status' , 'bbloomer_get_overall_stock_status', 9999, 2 );

function bbloomer_get_overall_stock_status( $status, $product ) {
    if ( $product->get_type() === 'simple' && $product->managing_stock() ) {
        $stock = (int) $product->get_stock_quantity() + (int) get_post_meta( $product->get_id(), '_stock2', true );
        $status = $stock > 0 ? 'instock' : 'outofstock';
    }
    return $status;
}

// 订单完成后扣减简单产品库存
add_filter( 'woocommerce_payment_complete_reduce_order_stock', 'bbloomer_maybe_reduce_second_stock', 9999, 2 );

function bbloomer_maybe_reduce_second_stock( $reduce, $order_id ) {
    $order = wc_get_order( $order_id );
    $atleastastock2change = false;
    foreach ( $order->get_items() as $item ) {   
        if ( ! $item->is_type( 'line_item' ) ) {
            continue;
        }
        $product = $item->get_product();
        $item_stock_reduced = $item->get_meta( '_reduced_stock', true );
        if ( $item_stock_reduced || ! $product || ! $product->managing_stock() || $product->get_type() !== 'simple' ) {
            continue;
        }
        $qty = apply_filters( 'woocommerce_order_item_quantity', $item->get_quantity(), $order, $item );
        $stock1 = (int) get_post_meta( $product->get_id(), '_stock', true );
        if ( $qty <= $stock1 ) continue;
        $atleastastock2change = true;
    }
    if ( ! $atleastastock2change ) return $reduce;  
    foreach ( $order->get_items() as $item ) {   
        if ( ! $item->is_type( 'line_item' ) ) {
            continue;
        }
        $product = $item->get_product();
        $item_stock_reduced = $item->get_meta( '_reduced_stock', true );
        if ( $item_stock_reduced || ! $product || ! $product->managing_stock() || $product->get_type() !== 'simple' ) {
            continue;
        }  
        $item_name = $product->get_formatted_name();
        $qty = apply_filters( 'woocommerce_order_item_quantity', $item->get_quantity(), $order, $item );
        $stock1 = (int) get_post_meta( $product->get_id(), '_stock', true );
        $stock2 = (int) get_post_meta( $product->get_id(), '_stock2', true );
        if ( $qty <= $stock1 ) {
            wc_update_product_stock( $product, $qty, 'decrease' );
            $order->add_order_note( sprintf( '扣减产品"%s"库存:主仓库从"%s"变为"%s"。', $item_name, $stock1, $stock1 - $qty ) );
        } else {    
            $newstock2 = $stock2 - ( $qty - $stock1 );
            wc_update_product_stock( $product, $stock1, 'decrease' );
            update_post_meta( $product->get_id(), '_stock2', $newstock2 < 0 ? 0 : $newstock2 );
            $item->add_meta_data( '_reduced_stock', $qty, true );
            $item->save();          
            $order->add_order_note( sprintf( '扣减产品"%s"库存:主仓库从"%s"变为"0",第二个仓库从"%s"变为"%s"。', $item_name, $stock1, $stock2, $newstock2 < 0 ? 0 : $newstock2 ) );
        }
    }
    $order->get_data_store()->set_stock_reduced( $order_id, true );
    return false;
}

变体产品修复代码

原代码未处理选中变体后的库存计算,仅针对可变父产品做了逻辑处理,而用户选择变体后,页面实际加载的是variation类型的产品对象,需要单独为其添加库存计算逻辑。以下是修复后的完整代码:

// 添加第二个库存字段(变体产品)
add_action( 'woocommerce_variation_options_pricing', 'bbloomer_additional_stock_location_for_variable_variations', 10, 3 );
 
function bbloomer_additional_stock_location_for_variable_variations( $loop, $variation_data, $variation ) {
    woocommerce_wp_text_input(
        array(
            'id' => '_stock2_variable[' . $loop . ']',
            'value' => get_post_meta( $variation->ID, '_stock2_variable', true ),
            'label' => '第二个仓库库存',
            'data_type' => 'stock',
        )
    );
}
 
// 保存变体产品的第二个库存
add_action( 'woocommerce_save_product_variation', 'bbloomer_save_additional_stock_for_variable_variations', 10, 2 );
 
function bbloomer_save_additional_stock_for_variable_variations( $variation_id, $i ) {
    if ( isset( $_POST['_stock2_variable'][$i] ) ) {
        update_post_meta( $variation_id, '_stock2_variable', sanitize_text_field( $_POST['_stock2_variable'][$i] ) );
    }
}
 
// 计算总库存:处理可变父产品和单个变体
add_filter( 'woocommerce_product_get_stock_quantity' , 'bbloomer_get_overall_stock_quantity_variable', 9999, 2 );
 
function bbloomer_get_overall_stock_quantity_variable( $value, $product ) {
    // 处理单个变体
    if ($product->get_type() === 'variation') {
        $stock2 = (int) get_post_meta( $product->get_id(), '_stock2_variable', true );
        $value = (int) $value + $stock2;
    } 
    // 处理可变父产品(显示所有变体总库存)
    elseif ($product->get_type() === 'variable') {
        $stock2_total = 0;
        foreach ($product->get_available_variations() as $variation) {
            $stock2_total += (int) get_post_meta( $variation['variation_id'], '_stock2_variable', true );
        }
        $value = (int) $value + $stock2_total;
    }
    return $value;
}
 
// 更新库存状态:处理可变父产品和单个变体
add_filter( 'woocommerce_product_get_stock_status' , 'bbloomer_get_overall_stock_status_variable', 9999, 2 );
 
function bbloomer_get_overall_stock_status_variable( $status, $product ) {
    // 处理单个变体
    if ($product->get_type() === 'variation' && $product->managing_stock()) {
        $stock = (int) $product->get_stock_quantity() + (int) get_post_meta( $product->get_id(), '_stock2_variable', true );
        $status = $stock > 0 ? 'instock' : 'outofstock';
    }
    // 处理可变父产品
    elseif ($product->get_type() === 'variable' && $product->managing_stock()) {
        $total_stock = (int) $product->get_stock_quantity();
        foreach ($product->get_available_variations() as $variation) {
            $total_stock += (int) get_post_meta( $variation['variation_id'], '_stock2_variable', true );
            $total_stock += (int) get_post_meta( $variation['variation_id'], '_stock', true );
        }
        $status = $total_stock > 0 ? 'instock' : 'outofstock';
    }
    return $status;
}
 
// 订单完成后扣减变体产品库存
add_filter( 'woocommerce_payment_complete_reduce_order_stock', 'bbloomer_maybe_reduce_second_stock_variable', 9999, 2 );
 
function bbloomer_maybe_reduce_second_stock_variable( $reduce, $order_id ) {
    $order = wc_get_order( $order_id );
    foreach ( $order->get_items() as $item ) {  
        if ( ! $item->is_type( 'line_item' ) ) {
            continue;
        }
        $product = $item->get_product();
        if ( $product && $product->get_type() === 'variation' && $product->managing_stock() ) {
            $item_stock_reduced = $item->get_meta( '_reduced_stock_variable', true );
            if ( $item_stock_reduced ) {
                continue;
            }
            $qty = apply_filters( 'woocommerce_order_item_quantity', $item->get_quantity(), $order, $item );
            $stock1 = (int) get_post_meta( $product->get_id(), '_stock', true );
            $stock2 = (int) get_post_meta( $product->get_id(), '_stock2_variable', true );
            
            if ( $qty <= $stock1 ) {
                wc_update_product_stock( $product, $qty, 'decrease' );
                $order->add_order_note( sprintf( '扣减变体"%s"库存:主仓库从"%s"变为"%s"。', $item->get_name(), $stock1, $stock1 - $qty ) );
            } else {
                $used_stock2 = $qty - $stock1;
                $new_stock2 = $stock2 - $used_stock2;
                if ($new_stock2 < 0) $new_stock2 = 0;
                
                wc_update_product_stock( $product, $stock1, 'decrease' );
                update_post_meta( $product->get_id(), '_stock2_variable', $new_stock2 );
                
                $item->add_meta_data( '_reduced_stock_variable', $qty, true );
                $item->save();          
                $order->add_order_note( sprintf( '扣减变体"%s"库存:主仓库从"%s"变为"0",第二个仓库从"%s"变为"%s"。', $item->get_name(), $stock1, $stock2, $new_stock2 ) );
            }
        }
    }
    $order->get_data_store()->set_stock_reduced( $order_id, true );
    return false;
}

关键修复点

  1. 新增变体类型库存计算:在库存数量过滤钩子中添加对variation类型产品的处理,计算单个变体的双仓库库存总和。
  2. 修复变体库存状态判断:为单个变体补充库存状态逻辑,确保选中变体后正确显示有货/缺货状态。
  3. 优化库存扣减逻辑:完善变体库存扣减流程,优先扣减主仓库库存,剩余部分从第二个仓库扣除,避免出现负数库存。

内容的提问来源于stack exchange,提问作者Eryk Paśnik

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.27 04:05:53