【问题标题】:How to update similar variation stock after purchase in Woocommerce在 Woocommerce 中购买后如何更新类似的变体库存
【发布时间】:2019-06-26 22:34:39
【问题描述】:

我很难找到一种方法来更新产品类似变体的库存。

例如,我所有的产品都有一个主要变体,“黑色”(30 美元)或“白色”(250 美元),但有时它们还有另一个变体,即“日期开始”,所以 date_start:"12th June" ,date_start:“7 月 30 日”等。我需要更新“日期”变体的库存(如果没有日期,woocommerce 会更新主要库存,没问题)。 如果有人选择“黑色”+“6 月 12 日”,我需要将“6 月 12 日”的库存也减少为“白色”...

在有人问之前,“黑色”和“白色”每个产品的价格不同......而且每个产品的“日期”也会发生变化,这就是为什么我需要使用变体(而不是插件的附加属性)。 也许有人对组织这个有更好的想法,但我尝试了许多其他解决方案,总是一个警告。这个好像比较简单,只要找到好的“钩子”和“代码”就行了

这是我为此编写的一些伪代码:

if(Product is sold):
VarSoldVariation = getSoldVariation(product->ID);
OtherVariationWithSameDate = getVariations (VarSoldVariation->pa_dates);
foreach(OtherVariationWithSameDate)updateStockVariation();
endif;

【问题讨论】:

    标签: wordpress woocommerce hook-woocommerce


    【解决方案1】:

    好的,在这种情况下不使用元数据/属性而不是变体似乎有点奇怪。然而,我做了比这个更不寻常的变化,所以不用判断你的决定:

    首先,您必须找到一个合适的动作钩子,它会在订单发生后触发。其中一些是:

    更新 2:

    我重写了一些改进的代码:

      1234563而且我们也知道在可能的情况下使用wc_get_products and WC_Product_Query 是更好的做法。但是在这种情况下,甚至不需要对 db 进行直接后查询,并且可以从 WC_Product_Variableget_available_variations 方法中获得变化
    1. 现在它会检查订单项目的数量并将其用于其他日期变化的库存更新。

    2. 现在它尽可能使用 WC 类和函数,而不是直接更新元数据、库存数量、库存状态等。

    更新后的代码:

    add_action('woocommerce_order_status_processing', 'sync_variations_stock');
    
    /**
     * Update same date variations on customer order place
     * @param $order_id
     * @return void
     */
    function sync_variations_stock($order_id)
    {
        if (is_admin()) return; // make sure it's a user order and we aren't on admin dashboard
        $order = wc_get_order( $order_id );
        foreach( $order->get_items() as $item ) {
            if ($item->get_type() !== 'line_item') continue;    //if $item is not a product or variation
            $order_variation_count   = $item->get_quantity();
            $order_product_id        = $item->get_product_id();
            $order_variation_id      = $item->get_variation_id();
    
            if ( ! $order_variation_id ) continue;    // if the item isn't a variation
    
            $order_variation         = wc_get_product($order_variation_id);
            $order_variation_attribs = $order_variation->get_variation_attributes();
            if ( isset($order_variation_attribs['attribute_pa_date']) ) {
                $current_date_attrib = $order_variation_attribs['attribute_pa_date'];
            } else {
                continue; // stop if the variation in the order doesn't have 'pa_date' attrib
            }
    
            $product    = wc_get_product( $order_product_id );
            $variations = $product->get_available_variations();
            foreach ( $variations as $variation ) {
                if ( $variation['variation_id'] == $order_variation_id ) {
                    continue;   //if this variation is the one we have in our order
                }
                if ( ! isset( $variation['attributes']['attribute_pa_color'] ) || !isset( $variation['attributes']['attribute_pa_date'] ) ) {
                    continue;   //if this variation does not have the color or date attrib
                }
    
                if ( $variation['attributes']['attribute_pa_date'] == $current_date_attrib ) {
    
                    /*
                     * wc_update_product_stock function sets the stock quantity if the variation stock management is enabled
                     * NOTE: This function may cause a negative stock even if the variation backorder is set to false
                     */
                    wc_update_product_stock( $variation['variation_id'], $order_variation_count, 'decrease' );
                    wc_delete_product_transients($variation['variation_id']); // Clear/refresh the variation cache (optionally if needed)
                }
            }
        }
    }
    

    经过测试并且可以正常工作!

    我的第一个答案:

    对于这个例子,我将使用最后一个。但是,您应该小心注意这个钩子,因为它会在“WC 感谢页面”的每个页面加载时触发。最好使用以下钩子之一:
    woocommerce_order_status_processing
    woocommerce_order_status_completed
    woocommerce_payment_complete

    最终的代码是这样的:

    add_action('woocommerce_thankyou', 'sync_variations_stock');
    
    function sync_variations_stock($order_id)
    {
        $order = wc_get_order( $order_id );
        foreach( $order->get_items() as $item ){
            $product_id = $item->get_product_id();
            $product_variation_id = $item->get_variation_id();
    
            if (!$product_variation_id) return; // if the item isn't a variation
    
            $date_variation = get_post_meta( $product_variation_id, 'attribute_pa_date', true);
            $color_variation = get_post_meta( $product_variation_id, 'attribute_pa_color', true);
    
            if ( ! $date_variation && ! $color_variation ) return;  //if the variation doesn't have date and color attributes
    
            $args = array(
                'post_parent' => $product_id,
                'post_type' => 'product_variation',
                'posts_per_page' => -1,
                'meta_query' => array(
                    array(
                        'key' => 'attribute_pa_date',
                        'value' => $date_variation,
                        'compare' => '='
                    ),
                    array(
                        'key' => 'attribute_pa_color',
                        'value' => $color_variation,
                        'compare' => '!='
                    )
                ),
            );
            $other_date_variations = get_posts($args);
    
            if( is_array($other_date_variations) && !empty($other_date_variations) ){
                foreach ($other_date_variations as $date_variation) {
    
                    // do your stock updating proccess here. (updateStockVariation() as you write in your code)
    
                    $variation_id = $date_variation->ID;
                    $date_variation_stock = (int) get_post_meta( $variation_id, '_stock', true);
                    if ($date_variation_stock > 0) {    //to prevent backorders
                        $date_variation_stock =  $date_variation_stock - 1;
                        update_post_meta($variation_id, '_stock', $date_variation_stock);
    
                        // if the variation is now out-of-stock, set it as so
                        if ($date_variation_stock === 0) {
                            update_post_meta($variation_id, '_stock_status', 'outofstock');
                            wp_set_post_terms( $variation_id, 'outofstock', 'product_visibility', true );
                        }
                    }
                }
            }
        }
    }
    

    注意:您必须替换 attribute_pa_dateattribute_pa_color 以匹配您的属性 slug。

    更新 1
    在这个主题中还有其他考虑。 WC Variation 库存数量可能会在其他场景和情况下发生变化,例如仪表板上的订单编辑、订单退款、直接产品编辑等。在上线之前,您也必须考虑这些。
    正如我所说的那样,可能还有其他方法可以做你想做的事情。但我无法理解您的设置以及您的变体与日期之间的关系。我认为最好在 WB.SE 上提出与方法相关的问题

    【讨论】:

    • 好吧,你为什么建议我使用元数据/属性?我需要一个变体的不同价格和另一个变体的库存管理,所以我认为这就是它更复杂并且我不能使用元数据/属性的原因。如果你有更好的想法,我来了! :) 我真的在努力解决这个问题。最奇怪的是,您可以在创建产品时为两个变体之一选择“任何”,所以我认为它可以开箱即用,但遗憾的是不是......
    • 只想补充一句“谢谢”,因为它运行良好。我想用一些“woocommerce”功能(比如 $product_variation = new WC_Product_Variation( $product_variation_id ); )来改变它,但现在就这样吧,因为我时间紧迫。再次感谢。
    • 我很高兴它有帮助。请注意,我已经用一些附加说明更新了我的答案。
    • 谢谢。我只需要考虑添加退款代码。我认为我的问题描述在这里更好地描述:wordpress.org/support/topic/need-help-with-variation-and-stock/…
    • 我已经用更好的方法完全更新了我的答案。如果它是您正在寻找的,请使其成为公认的答案。也许更改您在 wordpress.org 上发布的代码并在此处提及此问题的链接是个好主意:)
    【解决方案2】:

    我也只是做了一个小改动。在您的代码中,如果人们刷新页面,则其他变体的库存会减少...由于 woocommerce 总是会首先减少已购买变体的库存,因此我会获取此库存变体编号并用它更新其他变体。所以我确信一切都保持不变。 :) 这是更新的代码:

        function sync_variations_stock($order_id)
        {
            if (is_admin()) return; // make sure it's a user order and we aren't on admin dashboard
            $order = wc_get_order( $order_id );
            foreach( $order->get_items() as $item ) {
                if ($item->get_type() !== 'line_item') continue;    //if $item is not a product or variation
                $order_variation_count   = $item->get_quantity();
                $order_product_id        = $item->get_product_id();
                $order_variation_id      = $item->get_variation_id();
    
                if ( ! $order_variation_id ) continue;    // if the item isn't a variation
    
                $order_variation         = wc_get_product($order_variation_id);
                $order_variation_attribs = $order_variation->get_variation_attributes();
                if ( isset($order_variation_attribs['attribute_pa_dates']) ) {
                    $current_date_attrib = $order_variation_attribs['attribute_pa_dates'];
    //Get the stock of the current variation for updating others.
                    $new_stock = $order_variation->get_stock_quantity();
                } else {
                    continue; // stop if the variation in the order doesn't have 'pa_dates' attrib
                }
    
                $product    = wc_get_product( $order_product_id );
                $variations = $product->get_available_variations();
                foreach ( $variations as $variation ) {
                    if ( $variation['variation_id'] == $order_variation_id ) {
                        continue;   //if this variation is the one we have in our order
                    }
                    if ( ! isset( $variation['attributes']['attribute_pa_admissible-emploi-quebec'] ) || !isset( $variation['attributes']['attribute_pa_dates'] ) ) {
                        continue;   //if this variation does not have the color or date attrib
                    }
    
                    if ( $variation['attributes']['attribute_pa_dates'] == $current_date_attrib ) {
    
                        /*
                         * wc_update_product_stock function sets the stock quantity if the variation stock management is enabled
                         * NOTE: This function may cause a negative stock even if the variation backorder is set to false
                         */
                        //wc_update_product_stock( $variation['variation_id'], $order_variation_count, 'decrease' );
    //Update stock of other variation with the stock number of the one just bought
                        wc_update_product_stock( $variation['variation_id'], $new_stock, 'set' );
                        wc_delete_product_transients($variation['variation_id']); // Clear/refresh the variation cache (optionally if needed)
                    }
                }
            }
        }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-10-10
      • 2023-03-13
      • 1970-01-01
      • 1970-01-01
      • 2023-03-10
      • 2023-04-02
      • 1970-01-01
      • 2022-01-11
      相关资源
      最近更新 更多