应用优惠券代码后更改 WooCommerce 购物车价格

发布于 2025-01-09 22:27:09 字数 2751 浏览 0 评论 0原文

我在 WooCommerce 上创建了一个产品,并使用钩子 woocommerce_before_add_to_cart_button 在产品详细信息页面上添加了两个选项。现在,当客户从产品详细信息页面将产品添加到购物车时,他们有两个选择。他们可以从这两个选项中选择一个。

然后,我使用 woocommerce 挂钩 woocommerce_add_cart_item_data 将用户选择的值存储在购物车元中。

我正在使用这个答案中的代码: 将产品自定义字段单选按钮值保存在购物车中并将其显示在购物车页面上

这是我的代码:

// single Product Page options  
add_action("woocommerce_before_add_to_cart_button", "options_on_single_product");
function options_on_single_product(){
    $dp_product_id = get_the_ID(); 
    $product_url = get_permalink($dp_product_id);

    ?>
        <input type="radio" name="custom_options" checked="checked" value="option1"> option1<br />
        <input type="radio" name="custom_options" value="option2"> option2
    <?php
}


//Store the custom field
add_filter( 'woocommerce_add_cart_item_data', 'save_custom_data_with_add_to_cart', 10, 2 );
function save_custom_data_with_add_to_cart( $cart_item_meta, $product_id ) {
    global $woocommerce;
    $cart_item_meta['custom_options'] = $_POST['custom_options'];
    return $cart_item_meta; 
}

这是我尝试过的:

add_action( 'woocommerce_before_calculate_totals', 'add_custom_price', 10, 1);
function add_custom_price( $cart_obj ) {

    if ( is_admin() && ! defined( 'DOING_AJAX' ) )
        return;

    foreach ( $cart_obj->get_cart() as $key => $value ) {
        $product_id = $value['product_id'];
        $custom_options = $value['custom_options'];
        $coupon_code = $value['coupon_code'];
        if($custom_options == 'option2')
        {
            if($coupon_code !='')
            {
                global $woocommerce;
                if ( WC()->cart->has_discount( $coupon_code ) ) return;
                (WC()->cart->add_discount( $coupon_code ))

            //code for second discount
            }
            else{
                $percentage = get_post_meta( $product_id , 'percentage', true );
                //print_r($value);
                $old_price = $value['data']->regular_price;
                $new_price = ($percentage / 100) * $old_price;
                $value['data']->set_price( $new_price );
            }
        } 
    }
}

现在我想通过最后一个片段得到的是:

  • 如果客户选择了 Option1,则运行 woocommerce 常规流程。
  • 如果选择选项 2,则首先将优惠券代码应用于购物车(如果客户输入代码),然后将价格除以一定百分比(存储在产品元数据中)然后应用

但它没有按预期工作,因为更改后的产品价格是之前的,优惠券折扣是在此更改后的价格上应用的。

我想要的是,优惠券折扣将首先应用于产品正常价格,然后在更改此价格后使用我的自定义产品折扣。

这可能吗?我怎样才能做到这一点?

谢谢。

I have created a product on WooCommerce, and added two options on product detail page using the hook woocommerce_before_add_to_cart_button. Now when customers add product to cart from product detail page they have two options their. They can choose one option from these two options.

Then I have stored the user selected value in cart meta using the woocommerce hook woocommerce_add_cart_item_data.

I am using the code from this answer: Save product custom field radio button value in cart and display it on Cart page

This is my code:

// single Product Page options  
add_action("woocommerce_before_add_to_cart_button", "options_on_single_product");
function options_on_single_product(){
    $dp_product_id = get_the_ID(); 
    $product_url = get_permalink($dp_product_id);

    ?>
        <input type="radio" name="custom_options" checked="checked" value="option1"> option1<br />
        <input type="radio" name="custom_options" value="option2"> option2
    <?php
}


//Store the custom field
add_filter( 'woocommerce_add_cart_item_data', 'save_custom_data_with_add_to_cart', 10, 2 );
function save_custom_data_with_add_to_cart( $cart_item_meta, $product_id ) {
    global $woocommerce;
    $cart_item_meta['custom_options'] = $_POST['custom_options'];
    return $cart_item_meta; 
}

And this is what I have tried:

add_action( 'woocommerce_before_calculate_totals', 'add_custom_price', 10, 1);
function add_custom_price( $cart_obj ) {

    if ( is_admin() && ! defined( 'DOING_AJAX' ) )
        return;

    foreach ( $cart_obj->get_cart() as $key => $value ) {
        $product_id = $value['product_id'];
        $custom_options = $value['custom_options'];
        $coupon_code = $value['coupon_code'];
        if($custom_options == 'option2')
        {
            if($coupon_code !='')
            {
                global $woocommerce;
                if ( WC()->cart->has_discount( $coupon_code ) ) return;
                (WC()->cart->add_discount( $coupon_code ))

            //code for second discount
            }
            else{
                $percentage = get_post_meta( $product_id , 'percentage', true );
                //print_r($value);
                $old_price = $value['data']->regular_price;
                $new_price = ($percentage / 100) * $old_price;
                $value['data']->set_price( $new_price );
            }
        } 
    }
}

Now what I am trying to get with that last snippet is:

  • If Option1 is selected by the customer then woocommerce regular process is run.
  • If Option2 is selected then firstly coupon code applied to cart (if code entered by the customer) and then the price is divide by some percentage (stored in product meta) is applied afterward.

But it’s not working as expected because the changed product price is maid before and coupon discount is applied after on this changed price.

What I would like is that the coupon discount will be applied first on the product regular price and then after change this price with my custom product discount.

Is this possible? How can I achieve that?

Thanks.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

太阳公公是暖光 2025-01-16 22:27:09

这实际上不可能……为什么? …因为(逻辑):

  1. 您有产品价格
  2. 然后优惠券折扣将应用于该价格(之后)
    ==>如果您更改产品价格,优惠券将应用于更改后的价格

您可以做什么:

  1. 您不会更改产品价格
  2. 如果输入了优惠券,
  3. 并且...如果“option2”产品已添加到购物车:
  4. 根据使用 WC_cart add_fee() 方法…

对于最后一种情况,您将必须微调您的额外折扣。
如果优惠券尚未使用或已被删除,则不会有额外折扣。

您的自定义函数将被挂钩到 woocommerce_cart_calculate_fees 操作挂钩中:

add_action( 'woocommerce_cart_calculate_fees', 'option2_additional_discount', 10, 1 );
function option2_additional_discount( $cart_obj ) {

    if ( is_admin() && ! defined( 'DOING_AJAX' ) )
        return;

    $discount = 0;
    $applied_coupons = $cart_obj->get_applied_coupons();

    foreach ( $cart_obj->get_cart() as $item_values ) {
        if( 'option2' == $item_values['custom_options'] && !empty($applied_coupons) ){
            $product_id = $item_values['product_id'];
            $percentage = get_post_meta( $product_id , 'percentage', true );
            $quantity = $item_values['quantity'];
            $product_reg_price = $item_values['data']->regular_price;
            $line_total = $item_values['line_total'];
            $line_subtotal = $item_values['line_subtotal'];
            $percentage = 90;

            ## ----- CALCULATIONS (To Fine tune) ----- ##

            $item_discounted_price = ($percentage / 100) *  $product_reg_price * $item_values['quantity'];
            // Or Besed on line item subtotal
            $discounted_price = ($percentage / 100) * $line_subtotal;

            $discount += $product_reg_price - $item_discounted_price;
        }
    }
    if($discount != 0)
        $cart_obj->add_fee( __( 'Option2 discount', 'woocommerce' ) , - $discount );
}

代码位于活动子主题(或主题)的 function.php 文件中或任何插件中文件。

该代码经过测试并且可以工作。

This is not really possible … Why? … Because (the logic):

  1. You have the product price
  2. Then the coupon discount is applied to that price (afterwards)
    ==> if you change the product price, the coupon is will be applied to that changed price

What you can do instead:

  1. You don't change product price
  2. if entered the coupon is applied and …
  3. If "option2" product is added to cart:
  4. Apply a custom discount (a negative fee) based on the product price added after using WC_cart add_fee() method…

For this last case you will have to fine tune your additional discount.
If the coupon has not been applied or it's removed there is no additional discount.

Your custom function will be hooked in woocommerce_cart_calculate_fees action hook instead:

add_action( 'woocommerce_cart_calculate_fees', 'option2_additional_discount', 10, 1 );
function option2_additional_discount( $cart_obj ) {

    if ( is_admin() && ! defined( 'DOING_AJAX' ) )
        return;

    $discount = 0;
    $applied_coupons = $cart_obj->get_applied_coupons();

    foreach ( $cart_obj->get_cart() as $item_values ) {
        if( 'option2' == $item_values['custom_options'] && !empty($applied_coupons) ){
            $product_id = $item_values['product_id'];
            $percentage = get_post_meta( $product_id , 'percentage', true );
            $quantity = $item_values['quantity'];
            $product_reg_price = $item_values['data']->regular_price;
            $line_total = $item_values['line_total'];
            $line_subtotal = $item_values['line_subtotal'];
            $percentage = 90;

            ## ----- CALCULATIONS (To Fine tune) ----- ##

            $item_discounted_price = ($percentage / 100) *  $product_reg_price * $item_values['quantity'];
            // Or Besed on line item subtotal
            $discounted_price = ($percentage / 100) * $line_subtotal;

            $discount += $product_reg_price - $item_discounted_price;
        }
    }
    if($discount != 0)
        $cart_obj->add_fee( __( 'Option2 discount', 'woocommerce' ) , - $discount );
}

Code goes in function.php file of your active child theme (or theme) or also in any plugin file.

This code is tested and works.

那些过往 2025-01-16 22:27:09

使用 WC_Cart->add_fee() 方法添加负费用对我来说不起作用。当我检查 WC Cart 类别时,它甚至声明您不允许使用负金额。

请参阅文档。

我执行了以下操作:

  • 使用“安全”代码创建占位符优惠券,例如 custom_discount_fjgndfl28。将折扣金额设置为 0,这样当有人(以某种方式)在您的程序之外使用此优惠券时,折扣仍为 0。
  • 使用过滤器 woocommerce_get_shop_coupon_data,并为该优惠券/会话设置您想要的所有优惠券数据。
  • 挂钩 woocommerce_before_calculate_totals 并将您的自定义优惠券设置到购物车。
  • 此时,购物车应该正确计算所有内容。当它成为订单时,它也有正确的折扣金额。
  • 注意:优惠券代码在某些模板中也用作标签。使用过滤器 woocommerce_cart_totals_coupon_label 进行更改。

示例函数:

/**
 * NOTE: All the hooks and filters below have to be called from your own
 * does_it_need_custom_discount() function. I used the 'wp' hook for mine.
 * Do not copy/paste this to your functions.php.
**/

add_filter('woocommerce_get_shop_coupon_data', 'addVirtualCoupon', 10, 2);
function addVirtualCoupon($unknown_param, $curr_coupon_code) {

    if($curr_coupon_code == 'custom_discount_fjgndfl28') {

      // possible types are: 'fixed_cart', 'percent', 'fixed_product' or 'percent_product.
      $discount_type = 'fixed_cart'; 

      // how you calculate the ammount and where you get the data from is totally up to you.
      $amount = $get_or_calculate_the_coupon_ammount;

      if(!$discount_type || !$amount) return false;

        $coupon = array(
            'id' => 9999999999 . rand(2,9),
            'amount' => $amount,
            'individual_use' => false,
            'product_ids' => array(),
            'exclude_product_ids' => array(),
            'usage_limit' => '',
            'usage_limit_per_user' => '',
            'limit_usage_to_x_items' => '',
            'usage_count' => '',
            'expiry_date' => '',
            'apply_before_tax' => 'yes',
            'free_shipping' => false,
            'product_categories' => array(),
            'exclude_product_categories' => array(),
            'exclude_sale_items' => false,
            'minimum_amount' => '',
            'maximum_amount' => '',
            'customer_email' => '',
            'discount_type' => $discount_type,
        );

        return $coupon;
    }
}

add_action('woocommerce_before_calculate_totals', 'applyFakeCoupons');
function applyFakeCoupons() {
  global $woocommerce;
  // $woocommerce->cart->remove_coupons(); remove existing coupons if needed.
  $woocommerce->cart->applied_coupons[] = $this->coupon_code; 
}

add_filter( 'woocommerce_cart_totals_coupon_label', 'cart_totals_coupon_label', 100, 2 );
function cart_totals_coupon_label($label, $coupon) {

    if($coupon) {
      $code = $coupon->get_code();
      if($code == 'custom_discount_fjgndfl28') {
        return 'Your custom coupon label';
      }
    }

    return $label;
}

请注意:我从一个处理更多内容的类中复制了这些函数,这只是为了帮助您开始。

Adding a negative fee using the WC_Cart->add_fee() method wasn't working for me. When i check the WC Cart class, it even states you are not allowed to use a negative ammount.

See the docs.

I did the following:

  • create a placeholder coupon with a 'secure' code, e.g. custom_discount_fjgndfl28. Set a discount ammount of 0, so when somebody (somehow) uses this coupon outside your program the discount is still 0.
  • Use filter woocommerce_get_shop_coupon_data, and set all the coupon data you want for that coupon/session.
  • Hook into woocommerce_before_calculate_totals and set your custom coupon to the cart.
  • At this point the Cart should calculate everything correctly. And when it becomes an order, it also has the correct discount ammount.
  • Note: the coupon code is also used as a label in some templates. Use filter woocommerce_cart_totals_coupon_label to change it.

Example functions:

/**
 * NOTE: All the hooks and filters below have to be called from your own
 * does_it_need_custom_discount() function. I used the 'wp' hook for mine.
 * Do not copy/paste this to your functions.php.
**/

add_filter('woocommerce_get_shop_coupon_data', 'addVirtualCoupon', 10, 2);
function addVirtualCoupon($unknown_param, $curr_coupon_code) {

    if($curr_coupon_code == 'custom_discount_fjgndfl28') {

      // possible types are: 'fixed_cart', 'percent', 'fixed_product' or 'percent_product.
      $discount_type = 'fixed_cart'; 

      // how you calculate the ammount and where you get the data from is totally up to you.
      $amount = $get_or_calculate_the_coupon_ammount;

      if(!$discount_type || !$amount) return false;

        $coupon = array(
            'id' => 9999999999 . rand(2,9),
            'amount' => $amount,
            'individual_use' => false,
            'product_ids' => array(),
            'exclude_product_ids' => array(),
            'usage_limit' => '',
            'usage_limit_per_user' => '',
            'limit_usage_to_x_items' => '',
            'usage_count' => '',
            'expiry_date' => '',
            'apply_before_tax' => 'yes',
            'free_shipping' => false,
            'product_categories' => array(),
            'exclude_product_categories' => array(),
            'exclude_sale_items' => false,
            'minimum_amount' => '',
            'maximum_amount' => '',
            'customer_email' => '',
            'discount_type' => $discount_type,
        );

        return $coupon;
    }
}

add_action('woocommerce_before_calculate_totals', 'applyFakeCoupons');
function applyFakeCoupons() {
  global $woocommerce;
  // $woocommerce->cart->remove_coupons(); remove existing coupons if needed.
  $woocommerce->cart->applied_coupons[] = $this->coupon_code; 
}

add_filter( 'woocommerce_cart_totals_coupon_label', 'cart_totals_coupon_label', 100, 2 );
function cart_totals_coupon_label($label, $coupon) {

    if($coupon) {
      $code = $coupon->get_code();
      if($code == 'custom_discount_fjgndfl28') {
        return 'Your custom coupon label';
      }
    }

    return $label;
}

Please Note: i copied these functions out of a class that handles much more, it's only to help you get going.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文