WooCommerce 根据用户输入字段动态产品计算价格

问题描述 投票:0回答:1

在我的 WooCommerce 商店中,我有 15 种产品,每种产品应具有超过 2K 的变体(WooCommerce 允许创建最多 50 个变体),因此我使用了产品额外选项插件并创建了一些输入来检索客户输入。

  • 这些产品输入字段是:
    • 宽度,
    • 高度,
    • 厚度,
    • 材料密度(“MDF”= 760,“刨花板”= 680)。
  • 重量计算:(W x H x T x MD) / 1 000 000 000,
  • 费率计算:体重x身高,

价格将基于费率范围,例如:

  • 案例1:2600 <= Rate <= 5349 then price = 1000 ,
  • 案例2:5350<= Rate <= 8999 then price = 2000 ,
  • 案例3:9000 <= Rate <= 17250 then price = 3000.

这是产品输入字段 HTML:

<table class="thwepo-extra-options thwepo_simple" cellspacing="0">
    <tbody>
        <tr class="">
            <td class="label leftside">
                <label class="label-tag">Door height (mm)</label>
                <abbr class="required" title="Required">*</abbr>
            </td>
            <td class="value leftside">
                <input type="text" id="height884" name="height" placeholder="Height" value="" class="thwepof-input-field validate-required">
            </td>
        </tr>
        <tr class="">
            <td class="label leftside">
                <label class="label-tag">Door width (mm)</label>
                <abbr class="required" title="Required">*</abbr>
            </td>
            <td class="value leftside">
                <input type="text" id="width784" name="width" placeholder="Width" value="" class="thwepof-input-field validate-required" maxlength="1800">
            </td>
        </tr>
        <tr class="">
            <td class="label leftside">
                <label class="label-tag">Thickness (mm)</label>
                <abbr class="required" title="Required">*</abbr>
            </td>
            <td class="value leftside">
                <input type="text" id="thickness334" name="thickness" placeholder="Thickness" value="" class="thwepof-input-field validate-required">
            </td>
        </tr>
        <tr class="">
            <td class="label leftside">
                <label class="label-tag">Material Type</label>
                <abbr class="required" title="Required">*</abbr>
            </td>
            <td class="value leftside">
                <select id="type_de_bois772" name="type_de_bois" placeholder="Agglo" value="Agglo" class="thwepof-input-field validate-required">
                    <option value="Agglo">Chipboard</option>
                    <option value="MDF">Medium (MDF)</option>
                </select>
            </td>
        </tr>
    </tbody>
</table>

这是我的 PHP 代码:

add_action('woocommerce_before_calculate_totals', 'update_product_price_based_on_weight');

function update_product_price_based_on_weight($cart) {
foreach ($cart->get_cart() as $cart_item_key => $cart_item) {
   // Get product object
   $product = $cart_item['data'];

   // Check if product is the one we want to modify
   if ($product->get_name() === 'SERVO-DRIVE for AVENTOS HF') {
       // Calculate weight based on inputs
       $height = $_POST['height']; // Assuming the form submits this data
       $width = $_POST['width'];
       $thickness = $_POST['thickness'];
       $material_type = $_POST['type_de_bois'];

       // Calculate density based on material type
       $density = ($material_type === 'MDF') ? 760 : 680;

       // Calculate weight
       $weight = ($height * $width * $thickness * $density) / 1000000000;
       $force = $weight * $height;
       // Adjust price based on weight
       if ($force >= 2600 && $force <= 5349) {
           $product->set_price(1000); // Adjust price for CASE 1
       } elseif ($force >= 5350 && $force <= 8999) {
           $product->set_price(2000); // Adjust price for CASE 2
       } elseif ($force >= 9000 && $force <= 17250) {
           $product->set_price(3000); // Adjust price for CASE 3
       }
   }
}

但我无法让它工作,无法设置正确的计算价格。我做错了什么?

php woocommerce product price input-field
1个回答
0
投票

在下面的代码中,根据您最后的评论,我使用 JavaScript 直接在产品页面上动态计算价格(基于您的计算算法)。您可能需要微调您的计算算法,因为当前的计算似乎不准确。

注意: 这不适用于购物车和结帐块,它适用于经典的 WooCommerce 购物车和结帐(基于模板)。

1)。管理员设置

首先,在管理员编辑产品页面中,我们添加一个复选框以启用产品的动态价格计算:

// Admin product edit page (Check box to enable dynamic price)
add_action( 'woocommerce_product_options_pricing', 'enabling_product_dynamic_price_calculation' );
function enabling_product_dynamic_price_calculation() {
    global $post, $product_object;

    woocommerce_wp_checkbox( array(
        'id'            => 'dynamic_price',
        'label'         => __( 'Dynamic price', 'woocommerce' ),
        'value'         => $product_object->get_meta('dynamic_price') ? 'yes' : 'no',
        'description'   => __( 'Enable dynamic calculated price based on user input fields.', 'woocommerce' ),
    ) );
}
// Admin product: Save dynamic price setting option
add_action( 'woocommerce_admin_process_product_object', 'save_product_dynamic_price_setting_option' );
function save_product_dynamic_price_setting_option( $product ) {
    $product->update_meta_data( 'dynamic_price', isset($_POST['dynamic_price']) && $_POST['dynamic_price'] === 'yes' ? '1' : '' );
}

您将得到:

您需要在正常价格中设置该产品的起始(最低)价格金额。

2)。存档页面和产品默认显示价格

然后在商店和存档页面上,对于该产品,我们将添加到购物车按钮更改为产品页面的链接按钮。此外,我们还更改了价格显示,在常规价格中添加了“起始于”前缀:

// Replace loop add to cart button link with a link to the product
add_filter( 'woocommerce_loop_add_to_cart_link', 'replace_product_loop_add_to_cart_link', 100, 3 );
function replace_product_loop_add_to_cart_link( $button, $product, $args ) {
    // Only for external products
    if ( $product->get_meta('dynamic_price') ) {
        $button = sprintf( '<a href="%s" class="%s" %s>%s</a>',
            esc_url( $product->get_permalink() ),
            esc_attr( 'button' ),
            isset( $args['attributes'] ) ? wc_implode_html_attributes( $args['attributes'] ) : '',
            esc_html__( 'Select options', 'woocommerce' )
        );
    }
    return $button;
}

// Prefixing product price
add_filter( 'woocommerce_get_price_html', 'filter_get_price_html_callback', 10, 2 );
function filter_get_price_html_callback( $price_html, $product ){
    if( $product->get_meta('dynamic_price') ) {
        $price_html = sprintf('Starting from %s', $price_html);
    }
    return $price_html;
}

您将得到:

3)。单一产品输入字段(动态价格计算)

填充所有输入字段后,将计算并显示价格(替换“起始于”默认起始价格)

// Utility function (your custom input fields settings)
function get_custom_fields_data( $options = false ) {
    if ( $options ) {
        return array( 
            ''    => __('Select an option'), 
            '680' => __('Chipboard'), 
            '760' => __('Medium (MDF)'),
        );
    }

    return array(
        'height'    => array( 'field' => 'height',    'type' => 'text',   'label' => __('Door height (mm)'),   'name' => __('Height'), ),
        'width'     => array( 'field' => 'width',     'type' => 'text',   'label' => __('Door width (mm)'),    'name' => __('width'), ),
        'thickness' => array( 'field' => 'thickness', 'type' => 'text',   'label' => __('Thickness (mm)'),     'name' => __('Thickness'), ),
        'material'  => array( 'field' => 'material',  'type' => 'select', 'label' => __('Material Type (mm)'), 'name' => __('Material'), ),
    );
}

// Display custom input fields in single product pages
add_action('woocommerce_before_add_to_cart_button', 'action_before_add_to_cart_button', 20);
function action_before_add_to_cart_button() {
    global $product;

    if ( $product->get_meta('dynamic_price') ) {
        echo '<div class="custom-fields">';

        foreach ( get_custom_fields_data() as $key => $values ) {
            $args = array(
                'type'          => $values['type'],
                'label'         => $values['label'],
                'class'         => array( 'form-row-wide') ,
                'placeholder'   => $values['type'] === 'text' ? $values['name'] : '', // Optional
                'required'      => true,
            );

            if ( $values['type'] === 'select' ) { 
                $args['options'] = get_custom_fields_data( true );
            }

            woocommerce_form_field( $key, $args );
        } 
        echo '<input type="hidden" name="price" value="" />
        ' . product_price_calculation_js( $product ) . '
        </div>';
    }
}

// Custom function that calculates the product price
function product_price_calculation_js( $product ) {
    $zero_price = str_replace('0.00', '<span class="price-amount"></span>', wc_price(0));
    ob_start();
    ?>
    <script>
    jQuery(function($){
        var height = 0, width = 0, thickness = 0, density = 0, price = 0;
        var originalPrice = $('p.price').html(), zeroPrice = '<?php echo $zero_price; ?>';

        // Function that calculates the price
        function calculatePrice( height, width, thickness, density ) {
            var   price  = 0;

            if ( height > 0 && width > 0 && thickness > 0 && density > 0 ) {
                const weight = (height * width * thickness * density) / 1000000000,
                      rate   = weight * height;

                if ( rate < 5350 ) {
                    price = 1000.00; 
                } else if (rate >= 5350 && rate < 9000) {
                    price = 2000.00; 
                } else if (rate >= 9000) {
                    price = 3000.00; 
                }
            }
            return price;
        }

        $('form.cart').on('change mouseleave', '.custom-fields input[type=text], .custom-fields select', function(){
            const fieldValue = $(this).val(),   fieldKey = $(this).prop('name');

            if ( fieldValue > 0 ) {
                if ( fieldKey === 'height' ) {
                    height = fieldValue; 
                } else if ( fieldKey === 'width' ) {
                    width = fieldValue; 
                } else if ( fieldKey === 'thickness' ) {
                    thickness = fieldValue; 
                } else if ( fieldKey === 'material' ) {
                    density = fieldValue; 
                }
                price = calculatePrice( height, width, thickness, density );

                if ( price > 0 ) {
                    $('.custom-fields input[name=price]').val(price);
                    $('p.price').html(zeroPrice);
                    $('p.price span.price-amount').html(parseFloat(price).toFixed(2).replace('.', ','));
                }
            } else {
                price = 0;
                $('p.price').html(originalPrice);
                $('.custom-fields input[name=price]').val('');
            }
        });
    });
    </script>
    <?php
    return ob_get_clean();
}

// Validate required product input fields
add_filter( 'woocommerce_add_to_cart_validation', 'single_product_custom_fields_validation', 10, 2 );
function single_product_custom_fields_validation( $passed, $product_id ) {
    $product = wc_get_product( $product_id );

    if ( $product->get_meta('dynamic_price') ) {
        foreach ( get_custom_fields_data() as $key => $values ) {
            if ( isset($_POST[$key]) && empty($_POST[$key]) ) {
                wc_add_notice( sprintf( __('%s is a required field.', 'woocommerce'), '<strong>'.$values['label'].'</strong>'), "error" );
                $passed = false;
            }
        }
    }
    return $passed;
}
4)。保存并显示客户在购物车和结帐中输入的数据
// Save custom fields as custom cart item data
add_filter('woocommerce_add_cart_item_data', 'add_custom_cart_item_data', 20, 2 );
function add_custom_cart_item_data( $cart_item_data, $product_id ) {
    foreach ( get_custom_fields_data() as $key => $values ) {
        if ( isset($_POST[$key]) && ! empty($_POST[$key]) ) {
            $cart_item_data['custom'][$key] = sanitize_text_field($_POST[$key]);
        }
    } 
    if ( isset($_POST['price']) && ! empty($_POST['price']) ) {
        $cart_item_data['custom']['price'] = sanitize_text_field($_POST['price']);
    }
    return $cart_item_data;
}

// Display custom fields in Cart and Checkout
add_filter( 'woocommerce_get_item_data', 'display_custom_cart_item_data', 20, 2 );
function display_custom_cart_item_data( $cart_data, $cart_item ) {
    $options = get_custom_fields_data(true);

    foreach ( get_custom_fields_data() as $key => $values) {
        if( isset($cart_item['custom'][$key]) ) {
            $cart_data[] = array(
                'key'   => $values['name'],
                'value' => $values['type'] === 'select' ? $options[$cart_item['custom'][$key]] : $cart_item['custom'][$key],
            );
        }
    }
    return $cart_data;
}

您将得到:

5)。在购物车、迷你购物车和结账页面设置计算价格
// Cart and mini cart displayed calculated price
add_filter( 'woocommerce_cart_item_price', 'display_cart_item_price_html', 20, 2 );
function display_cart_item_price_html( $price_html, $cart_item ) {
    if( isset($item['custom']['price']) ) {
        $args  = array( 'price' => $cart_item['custom']['price'] ); 

        if ( WC()->cart->display_prices_including_tax() ) {
            $price = wc_get_price_including_tax( $cart_item['data'], $args );
        } else {
            $price = wc_get_price_excluding_tax( $cart_item['data'], $args );
        }
        return wc_price( $price );
    }
    return $price_html;
}

// Change and set cart item custom calculated price
add_action('woocommerce_before_calculate_totals', 'set_custom_cart_item_price');
function set_custom_cart_item_price( $cart ) {
    if ( is_admin() && !defined('DOING_AJAX') )
        return;

    foreach ( $cart->get_cart() as $item_key => $item ) {
        if( isset($item['custom']['price']) ) {
            $item['data']->set_price($item['custom']['price']);
        }
    }
}
6)。保存客户输入的数据并显示在订单和电子邮件中
// Save and display custom fields (custom order item metadata)
add_action( 'woocommerce_checkout_create_order_line_item', 'save_order_item_custom_meta_data', 10, 4 );
function save_order_item_custom_meta_data( $item, $cart_item_key, $values, $order ) {
    foreach ( get_custom_fields_data() as $key => $data ) {
        $options = get_custom_fields_data(true);

        if( isset($values['custom'][$key]) ) {
            $meta_value = $data['type'] === 'select' ? $options[$values['custom'][$key]] : $values['custom'][$key];
            $item->update_meta_data($key, $meta_value); 
        }
    }
}

// Add readable "meta key" label name replacement
add_filter('woocommerce_order_item_display_meta_key', 'filter_wc_order_item_display_meta_key', 10, 3 );
function filter_wc_order_item_display_meta_key( $display_key, $meta, $item ) {
    if( $item->get_type() === 'line_item' ) {
        foreach ( get_custom_fields_data() as $key => $values ) {
            if( $meta->key === $key ) {
                $display_key = $values['name'];
            }
        }
    }
    return $display_key;
}

代码位于子主题的functions.php 文件中(或插件中)。已测试并有效。

© www.soinside.com 2019 - 2024. All rights reserved.