WooCommerce单个添加到购物车页面的产品动态定价

huangapple go评论70阅读模式
英文:

Product dynamic pricing in WooCommerce single add to cart page

问题

我正在尝试创建一个用于单品页面的WooCommerce插件。我需要将常规定价与自定义定价相加。我能够计算出常规价格和自定义价格的总和,但是当我点击“添加到购物车”时,无法在购物车中设置新的计算价格。

任何帮助都将不胜感激。

我尝试使用add_filter,但对我没有起作用。
英文:

I am trying to create a WooCommerce plugin for single product pages. I need to add up regular pricing with custom pricing. I was able to get the sum up of regular price with custom price, but when I click on "Add to Cart" I am not able to set up the new calculated price, in cart.

Any help is appreciated.

// WooCommerce activation
function custom_product_page()
{
    global $wpdb;
    global $product;
    wp_enqueue_style('my-plugin-styles', plugins_url('assets/css/diamond_style.css', __FILE__));

    if (class_exists('WooCommerce') && is_product()) {
        $product = wc_get_product(get_the_ID());

        $product_categories = wp_get_post_terms(get_the_ID(), 'product_cat');
        $is_ring = false;
        foreach ($product_categories as $product_category) {
            if ($product_category->slug === 'rings' || $product_category->slug === 'ring') {
                $is_ring = true;
                break;
            }
        }
        $table_name = $wpdb->prefix . 'diamond_purity';
        $ring_size_table = $wpdb->prefix . 'ring_size';

        // Show Metal Color only if the product category is "ring"
        if ($is_ring) {
            // Retrieve the latest gold rate
            $gold_rate_table = $wpdb->prefix . 'gold_rate';
            $gold_rate = $wpdb->get_var("SELECT final_price FROM $gold_rate_table ORDER BY id DESC LIMIT 1");

            // Get the net weight attribute
            $net_weight = $product->get_attribute('net-weight-g');

            // Get the regular price
            $regular_price = $product->get_regular_price();

            // Calculate the updated price
            $updated_price = ($gold_rate * $net_weight) + $regular_price;

            // Display the updated price
            echo '<p class="productprice">₹' . $updated_price . '</p>';

            $gross_weight = $product->get_attribute('gross-weight');
            echo 'Weight: ' . $gross_weight . ' g';

          

            // Update cart item price with the custom price
            add_filter('woocommerce_add_cart_item', function ($cart_item) use ($updated_price) {
                $cart_item['data']->set_price($updated_price);
                return $cart_item;
            });
        }
    }
}
add_action('woocommerce_single_product_summary', 'custom_product_page', 25);

I tried using add_filter but didn't work me.

答案1

得分: 3

我已经重新审查了你的代码,发现了一些错误、问题和缺失的部分。以下是修改建议:

在产品添加到购物车表单中添加一个隐藏的输入字段,以在添加到购物车操作时提交自定义价格。然后你就可以使用该自定义价格。

由于你似乎在插件中使用了你的代码,你应该在主要的插件文件中添加以下内容,以检查WooCommerce是否处于活动状态:

defined( 'ABSPATH' ) or exit;

// 确保 WooCommerce 处于活动状态
if ( ! in_array( 'woocommerce/woocommerce.php', apply_filters( 'active_plugins', get_option( 'active_plugins' ) ) ) ) {
    return;
}

将CSS样式文件添加到队列需要一个单独的函数(你可能需要在样式规则中进行一些CSS更改):

add_action( 'wp_enqueue_scripts', 'custom_product_pricing_css' );
function custom_product_pricing_css() {
    // 仅在产品单页上添加样式
    if( ! is_product() ) return;

    wp_enqueue_style('my-plugin-styles', plugins_url('assets/css/diamond_style.css', __FILE__));
}

对于你的自定义数据库查询,最好将每个查询放在单独的函数中(原因:代码的模块化):

function get_the_gold_rate() {
    global $wpdb;

    return $wpdb->get_var( "SELECT final_price FROM {$wpdb->prefix}gold_rate ORDER BY id DESC LIMIT 1");
}

以下是经过修改的代码函数,以不同的挂钩(其中我包含了在产品表单内部添加了一个必需的隐藏输入字段):

add_action('woocommerce_before_add_to_cart_button', 'add_to_cart_product_pricing');
function add_to_cart_product_pricing() {
    global $woocommerce, $product;

    if ( is_a($woocommerce, 'WooCommerce') && is_product() ) {

        // 定位“ring”或“rings”产品类别
        if ( has_term( array('ring', 'rings'), 'product_cat' ) ) {
            // 加载最新的黄金价格
            $gold_rate = (float) get_the_gold_rate();

            // 获取净重产品属性
            $net_weight = $product->get_attribute('net-weight-g');

            // 获取产品常规价格
            $regular_price = $product->get_regular_price();

            // 计算产品更新后的价格
            $updated_price = ($gold_rate * $net_weight) + $regular_price;

            // 获取显示的价格
            $args = array( 'price' => floatval( $updated_price ) );

            if ( 'incl' === get_option('woocommerce_tax_display_shop') ) {
                $displayed_price = wc_get_price_including_tax( $product, $args );
            } else {
                $displayed_price = wc_get_price_excluding_tax( $product, $args );
            }

            // 显示产品更新后的价格
            printf( '<p class="productprice">%s</p>', wc_price( $displayed_price ) );

            // 显示一个带有“updated_price”的隐藏输入字段作为值
            printf( '<input type="hidden" name="updated_price" value="%s" />', $updated_price );

            // 获取总重量产品属性
            $gross_weight = $product->get_attribute('gross-weight');

            // 显示总重量
            printf( '<p class="grossweight">' . __('Weight: %s g') . '</p>', $gross_weight );
        }
    }
}

现在,为了将更新后的价格作为自定义购物车项目数据包含,我们使用以下代码:

add_filter( 'woocommerce_add_cart_item_data', 'save_custom_cart_item_data', 10, 2 );
function save_custom_cart_item_data( $cart_item_data, $product_id ) {

    if( isset($_POST['updated_price']) && ! empty($_POST['updated_price'])  ) {
        // 在购物车项目中设置自定义数据
        $cart_item_data['updated_price'] = (float) wc_clean($_POST['updated_price']);

        // 使每个项目成为唯一的分隔的购物车项目
        $cart_item_data['unique_key'] = md5( microtime().rand() );
    }
    return $cart_item_data;
}

现在,我们可以在迷你购物车中显示带有这个自定义更新后的价格的项目:

add_action( 'woocommerce_cart_item_price', 'filter_cart_displayed_price', 10, 2 );
function filter_cart_displayed_price( $price, $cart_item ) {
    if ( isset($cart_item['updated_price']) ) {
        $args = array( 'price' => floatval( $cart_item['updated_price'] ) );

        if ( 'incl' === get_option('woocommerce_tax_display_cart') ) {
            $product_price = wc_get_price_including_tax( $cart_item['data'], $args );
        } else {
            $product_price = wc_get_price_excluding_tax( $cart_item['data'], $args );
        }
        return wc_price( $product_price );
    }
    return $price;
}

最后,我们将购物车项目价格设置为自定义更新后的价格:

add_action( 'woocommerce_before_calculate_totals', 'set_new_cart_item_updated_price' );
function set_new_cart_item_updated_price( $cart ) {
    if ( ( is_admin() && ! defined( 'DOING_AJAX' ) ) )
        return;

    if ( did_action( 'woocommerce_before_calculate_totals' ) >= 2 )
        return;

    // 遍历购物车项目并设置更新后的价格
    foreach ( $cart->get_cart() as $cart_item ) {
        // 设置新价格
        if( isset($cart_item['updated_price']) ){
            $cart_item['data']->set_price($cart_item['updated_price']);
        }
    }
}

将代码放入你的活动子主题的functions.php文件中(或者活动主题中),或者也可以放入一个插件中。已经经过测试,可以正常工作。

英文:

I have revisited your code, as there are some mistakes, errors and missing things. Here, what is missing is a hidden input field in product add to cart form, to post your custom price on add to cart action. Then you will be able to use that custom price.

As it seems that you are using your code in a plugin, you should start adding the following to the main plugin file, to check that WooCommerce is active:

defined( &#39;ABSPATH&#39; ) or exit;

// Make sure WooCommerce is active
if ( ! in_array( &#39;woocommerce/woocommerce.php&#39;, apply_filters( &#39;active_plugins&#39;, get_option( &#39;active_plugins&#39; ) ) ) ) {
	return;
}

Enqueuing a CSS styles file requires a separated function (you may need to make some CSS changes in your style rules):

add_action( &#39;wp_enqueue_scripts&#39;, &#39;custom_product_pricing_css&#39; );
function custom_product_pricing_css() {
    // Only on product single pages
    if( ! is_product() ) return;

    wp_enqueue_style(&#39;my-plugin-styles&#39;, plugins_url(&#39;assets/css/diamond_style.css&#39;, __FILE__));
}

For your custom database queries, is better to set each in a separated function (reason: code modularity):

function get_the_gold_rate() {
    global $wpdb;

    return $wpdb-&gt;get_var( &quot;SELECT final_price FROM {$wpdb-&gt;prefix}gold_rate ORDER BY id DESC LIMIT 1&quot;);
}

Here is your revisited code function, hooked in a different hook (where I include a mandatory hidden input field inside the product form):

add_action(&#39;woocommerce_before_add_to_cart_button&#39;, &#39;add_to_cart_product_pricing&#39;, );
function add_to_cart_product_pricing() {
    global $woocommerce, $product;

    if ( is_a($woocommerce, &#39;WooCommerce&#39;) &amp;&amp; is_product() ) {

        // Targeting &quot;ring&quot; or &quot;rings&quot; product category
        if ( has_term( array(&#39;ring&#39;, &#39;rings&#39;), &#39;product_cat&#39; ) ) {
            // Load the latest gold rate
            $gold_rate = (float) get_the_gold_rate();

            // Get net weight product attribute
            $net_weight = $product-&gt;get_attribute(&#39;net-weight-g&#39;);

            // Get product regular price
            $regular_price = $product-&gt;get_regular_price();

            // Calculate product updated price
            $updated_price = ($gold_rate * $net_weight) + $regular_price;

            // Get the displayed price 
            $args = array( &#39;price&#39; =&gt; floatval( $updated_price ) );

            if ( &#39;incl&#39; === get_option(&#39;woocommerce_tax_display_shop&#39;) ) {
                $displayed_price = wc_get_price_including_tax( $product, $args );
            } else {
                $displayed_price = wc_get_price_excluding_tax( $product, $args );
            }

            // Display product updated price
            printf( &#39;&lt;p class=&quot;productprice&quot;&gt;%s&lt;/p&gt;&#39;, wc_price( $displayed_price ) );

            // Display a hidden input field with the &quot;updated_price&quot; as value
            printf( &#39;&lt;input type=&quot;hidden&quot; name=&quot;updated_price&quot; value=&quot;%s&quot; /&gt;&#39;, $updated_price );
            
            // Get gross weight product attribute 
            $gross_weight = $product-&gt;get_attribute(&#39;gross-weight&#39;);

            // Display the Gross Weight
            printf( &#39;&lt;p class=&quot;grossweight&quot;&gt;&#39; . __(&#39;Weight: %s g&#39;) . &#39;&lt;/p&gt;&#39;, $gross_weight );
        }
    }
}

Now to include the updated price as custom cart item data, we use the following:

add_filter( &#39;woocommerce_add_cart_item_data&#39;, &#39;save_custom_cart_item_data&#39;, 10, 2 );
function save_custom_cart_item_data( $cart_item_data, $product_id ) {

    if( isset($_POST[&#39;updated_price&#39;]) &amp;&amp; ! empty($_POST[&#39;updated_price&#39;])  ) {
        // Set the custom data in the cart item
        $cart_item_data[&#39;updated_price&#39;] = (float) wc_clean($_POST[&#39;updated_price&#39;]);

        // Make each item as a unique separated cart item
        $cart_item_data[&#39;unique_key&#39;] = md5( microtime().rand() );
    }
    return $cart_item_data;
}

So we can now show in Minicart, items with this custom updated price:

add_action( &#39;woocommerce_cart_item_price&#39;, &#39;filter_cart_displayed_price&#39;, 10, 2 );
function filter_cart_displayed_price( $price, $cart_item ) {
    if ( isset($cart_item[&#39;updated_price&#39;]) ) {
        $args = array( &#39;price&#39; =&gt; floatval( $cart_item[&#39;updated_price&#39;] ) );

        if ( &#39;incl&#39; === get_option(&#39;woocommerce_tax_display_cart&#39;) ) {
            $product_price = wc_get_price_including_tax( $cart_item[&#39;data&#39;], $args );
        } else {
            $product_price = wc_get_price_excluding_tax( $cart_item[&#39;data&#39;], $args );
        }
        return wc_price( $product_price );
    }
    return $price;
}

And finally, we set the cart item price with the custom updated price:

add_action( &#39;woocommerce_before_calculate_totals&#39;, &#39;set_new_cart_item_updated_price&#39; );
function set_new_cart_item_updated_price( $cart ) {
    if ( ( is_admin() &amp;&amp; ! defined( &#39;DOING_AJAX&#39; ) ) )
        return;

    if ( did_action( &#39;woocommerce_before_calculate_totals&#39; ) &gt;= 2 )
        return;

    // Loop through cart items and set the updated price
    foreach ( $cart-&gt;get_cart() as $cart_item ) {
        // Set the new price
        if( isset($cart_item[&#39;updated_price&#39;]) ){
            $cart_item[&#39;data&#39;]-&gt;set_price($cart_item[&#39;updated_price&#39;]);
        }
    }
}

Code goes in functions.php file of your active child theme (or active theme) or in a plugin too. Tested and works.

Related: https://stackoverflow.com/questions/52303818/set-cart-item-price-from-a-hidden-input-field-custom-price-in-woocommerce-3/52304377#52304377

huangapple
  • 本文由 发表于 2023年6月22日 18:12:02
  • 转载请务必保留本文链接:https://go.coder-hub.com/76530827.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定