wordpress WooCommerce产品与自定义选择字段和价格计算问题

hvvq6cgz  于 2023-08-03  发布在  WordPress
关注(0)|答案(1)|浏览(132)

我在一个Woocommerce插件工作,我试图使产品页面上的自定义,但值是不是在页面上得到改变,当我做添加到购物车它需要两个值,即产品的价值已经在那里和定制后的产品价格。由于添加到购物车工程完美,但我只面临的问题,而添加custome价格后,产品定制。

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

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

        // Targeting "ring" or "rings" product category
        if (has_term(array('ring', 'rings'), 'product_cat')) {

            // Load 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 Metal Purity
            $metal_purity = $product->get_attribute('metal-purity');
            $metal_purity_table = $wpdb->prefix . 'diamond_purity';

            // Prepare the SQL query with proper escaping
            $query = $wpdb->prepare("SELECT percentage FROM $metal_purity_table WHERE purity = %s", $metal_purity);

            // Run the prepared query
            $metalpurity = $wpdb->get_var($query);

            $goldvalue = ($gold_rate * $metalpurity) / 100;

            // Diamond Shape
            $dquality = $product->get_attribute('diamond-quality');
            $sieves = $product->get_attribute('sieves');
            $dweight = $product->get_attribute('diamond-weight-ct');
            $dpieces = $product->get_attribute('diamond-pieces');

            $round_diamond_table = $wpdb->prefix . 'round_diamond';

            // Prepare the SQL query with proper escaping
            $query = $wpdb->prepare("SELECT $sieves FROM $round_diamond_table WHERE diamond_quality = %s", $dquality);

            // Run the prepared query
            $dshape = $wpdb->get_var($query);

            $dtotal = ($dshape * ($dweight / 5));
            $dmtotal = $dtotal * $dpieces;


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

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

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

            // Get the displayed 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);
            }

            // Display product updated price
            printf('<p class="productprice">%s</p>', wc_price($displayed_price));

            // Display a hidden input field with the "updated_price" as value
            printf('<input type="hidden" name="updated_price" value="%s" />', $updated_price);

            // Get gross weight product attribute 
            $gross_weight = $product->get_attribute('gross-weight');

            // Display the Gross Weight
            printf('<p class="grossweight">' . __('Weight: %s g') . '</p>', $gross_weight);
            // Store the updated price in a global variable
            global $updated_price;
        }
        
    }
}

add_action('woocommerce_single_product_summary', 'customization_of_product', 32);
function customization_of_product()
{
    global $product, $wpdb;
    if (has_term(array('ring', 'rings'), 'product_cat')) {
        echo '<div class="customization-form">
        <form id="customization-form" method="POST">
            <label for="ring-size">Ring Size:</label>';
            
    // Ring Size
    $ring_size_table = $wpdb->prefix . 'ring_size';
    $results = $wpdb->get_results("SELECT * FROM $ring_size_table");
    echo '<select name="ring-size" id="ring-size">
                <option value="">Ring Sizes</option>';
    foreach ($results as $result) {
        echo '<option value="' . $result->ring_size . '">' . $result->ring_size . '</option>';
    }
    echo '</select><br> <label for="metal-purity">Metal Purity:</label>';
    
    // Metal Purity
    $table_name = $wpdb->prefix . 'diamond_purity';
    $results = $wpdb->get_results("SELECT * FROM $table_name WHERE purity='14kt' OR purity='18kt'");
    echo '<select name="metal-purity" id="metal-purity">
                <option value="">Metal Purity</option>';
    foreach ($results as $result) {
        echo '<option value="' . $result->purity . '">' . $result->purity . '</option>';
    }
    echo '</select>';
    
    echo '<input type="submit" name="submit" value="Submit">
        </form>
    </div>';

    if (isset($_POST['submit'])) {
        // Get the submitted values
        $ring_size = $_POST['ring-size'];
        $metal_purity = $_POST['metal-purity'];

        // Calculate the updated price
        $updated_price = calculate_updated_price($product, $ring_size, $metal_purity);

         // Remove any existing items of the same product from the cart
         foreach (WC()->cart->get_cart() as $cart_item_key => $cart_item) {
            if ($cart_item['product_id'] === $product->get_id()) {
                WC()->cart->remove_cart_item($cart_item_key);
            }
        }
        // Set the updated price in the cart item data
        $cart_item_data = array(
            'updated_price' => $updated_price,
            'unique_key' => md5(microtime() . rand())
        );

        // Add the cart item
        WC()->cart->add_to_cart($product->get_id(), 1, 0, array(), $cart_item_data);

        // Get the updated cart value
        $updated_cart_value = WC()->cart->get_cart_total();

        // Display the updated cart value
        echo 'Updated Cart Value: ' . $updated_cart_value;
    }
    }

   
}
// Function to calculate the updated price
function calculate_updated_price($product, $ring_size, $metal_purity)
{
    global $wpdb;

    // Load 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 Metal Purity percentage
    $metal_purity_table = $wpdb->prefix . 'diamond_purity';
    $query = $wpdb->prepare("SELECT percentage FROM $metal_purity_table WHERE purity = %s", $metal_purity);
    $metal_purity_percentage = $wpdb->get_var($query);

    // Calculate gold value
    $gold_value = ($gold_rate * $metal_purity_percentage) / 100;
    

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

    // Get size gram variation
    $ring_size_table = $wpdb->prefix . 'ring_size';
    $query = $wpdb->prepare("SELECT variation_grams FROM $ring_size_table WHERE ring_size = %s", $ring_size);
    $ring_grams_percentage = $wpdb->get_var($query);

    // Get product regular price
    $regular_price = $product->get_regular_price();
    // Diamond Shape
    $dquality = $product->get_attribute('diamond-quality');
    $sieves = $product->get_attribute('sieves');
    $dweight = $product->get_attribute('diamond-weight-ct');
    $dpieces = $product->get_attribute('diamond-pieces');

    $round_diamond_table = $wpdb->prefix . 'round_diamond';

    // Prepare the SQL query with proper escaping
    $query = $wpdb->prepare("SELECT $sieves FROM $round_diamond_table WHERE diamond_quality = %s", $dquality);

    // Run the prepared query
    $dshape = $wpdb->get_var($query);

    $dtotal = ($dshape * ($dweight / 5));
    $dmtotal = $dtotal * $dpieces;


    $default_ring_size = $product->get_attribute('default-ring-size');
    if ($default_ring_size < $ring_size) {
        $netweight = $net_weight + $ring_grams_percentage;
       

        // Calculate product updated pric
        $updated_price = ($gold_value * $netweight) + $regular_price + $dmtotal;
    } elseif ($default_ring_size = $ring_size) {

        $updated_price = ($gold_value * $net_weight) + $regular_price + $dmtotal;
    } else {
        $netweight2 = $net_weight - $ring_grams_percentage;
        
        $updated_price = ($gold_value * $netweight2) + $regular_price + $dmtotal;
    }


    // Get the displayed 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);
    }

    // Display product updated price
    printf('<p class="productprice">%s</p>', wc_price($displayed_price));

    // Display a hidden input field with the "updated_price" as value
    printf('<input type="hidden" name="updated_price" value="%s" />', $updated_price);

    return $updated_price;
}

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'])) {
        // Set the custom data in the cart item
        $cart_item_data['updated_price'] = (float) wc_clean($_POST['updated_price']);

        // Make each item as a unique separated cart item
        $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;

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

字符串
我试着做:

// Calculate the updated price
    $updated_price = calculate_updated_price($product, $ring_size, $metal_purity);

     // Remove any existing items of the same product from the cart
     foreach (WC()->cart->get_cart() as $cart_item_key => $cart_item) {
        if ($cart_item['product_id'] === $product->get_id()) {
            WC()->cart->remove_cart_item($cart_item_key);
        }
    }`


但它同时接受初始值和定制值。

gzszwxb4

gzszwxb41#

这需要jQuery和 AJAX ,以使其按预期工作。
我已经重新访问了您的所有代码,将所有自定义SQL查询分离到各个函数中,现在可以重用了。
所有产品数据(产品属性、价格和黄金汇率)现在都在一个单独的(可重用的)函数中:
我已经删除了你的提交按钮(和自定义表单),移动了添加到购物车表单中的2个选择器,所以它们显示在添加到购物车按钮之前(在添加到购物车表单中)。在开始时,在每个选择字段上设置默认值(来自产品)(以前不是这种情况),因此不需要验证,因为总是会有选定的值。
现在,当客户选择其他东西时,价格将通过 AJAX 自动计算和更新。在 AJAX 过程中(2秒),表单上的所有内容都被阻塞(就像在checkout Ajax事件中一样)。
我已经用假值欺骗了你的自定义SQL查询,以检查一切正常。同样的事情。产品属性
下面是重新访问的代码:
Jquery( AJAX )外部文件名为“price-calculator.js”

jQuery( function($){
    if (typeof wc_add_to_cart_params === 'undefined')
        return false;

    var ringSize     = $('select#ring-size').val(),
        metalPurity  = $('select#metal-purity').val(),
        productId    = $('button[name=add-to-cart]').val();

    function sendSelectedData( ringSize, metalPurity, productId ) {
        $('form.cart').block({message: null, overlayCSS: {background: '#fff', opacity: 0.6}});
        $.ajax({
            type: 'POST',
            url: wc_add_to_cart_params.ajax_url,
            data: {
                'action':        'updating_price',
                'product_id':    productId,
                'ring_size':     ringSize,
                'metal_purity':  metalPurity 
            },
            success: function (res) {
                var response = $.parseJSON(res);
                $('input#updated_price').val(response['raw']);
                $('p.product-price').html(response['html']);
                $('form.cart').unblock();

                 console.log(response); // just for testing | TO BE REMOVED
            },
            error: function (err) {
                $('form.cart').unblock();

                 console.log(err); // just for testing | TO BE REMOVED
            }
        });
    }

    $('form.cart').on('change', 'select#ring-size', function(){
        ringSize = $(this).val();
        sendSelectedData( ringSize, metalPurity, productId );
    });

    $('form.cart').on('change', 'select#metal-purity', function(){
        metalPurity = $(this).val();
        sendSelectedData( ringSize, metalPurity, productId );
    });
});

字符串
PHP部分:

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

// Register main jQuery script (for a wp plugin)
add_action( 'wp_enqueue_scripts', 'add_ajax_price_calculation_js' );
function add_ajax_price_calculation_js() {
    // Only on front-end and checkout page
    if( ! is_admin() || ( is_checkout() && ! is_wc_endpoint_url() ) ) {
        // Load the datepicker jQuery-ui plugin script
        wp_enqueue_script( 'ajax-price-calculator',  plugins_url( 'assets/js/price-calculator.js', __FILE__ ), array('jquery'), false, true );
    }

}

// Utility function to get the gold rate from the database
function get_gold_rate() {
    global $wpdb;
    return $wpdb->get_var("SELECT final_price FROM {$wpdb->prefix}gold_rate ORDER BY id DESC LIMIT 1");
}

// Utility function to get the metal purity from the database
function get_metal_purity($metal_purity) {
    global $wpdb;
    return (float) $wpdb->get_var(
        $wpdb->prepare("
        SELECT percentage FROM {$wpdb->prefix}diamond_purity 
        WHERE purity = %s", $metal_purity)
    );
}

// Utility function to get the diamond shape from the database
function get_diamond_shape($diamond_sieves, $diamond_quality) {
    global $wpdb;
    return (float) $wpdb->get_var(
        $wpdb->prepare("
        SELECT {$diamond_sieves} FROM {$wpdb->prefix}round_diamond 
        WHERE diamond_quality = '%s'", $diamond_quality)
    );
}

// Utility function to get the ring sizes from the database
function get_ring_sizes() {
    global $wpdb;
    return $wpdb->get_col("SELECT ring_size FROM {$wpdb->prefix}ring_size");
}

// Utility function to get the metal purity from the database
function get_metal_purity_14k_18k() {
    global $wpdb;
    return $wpdb->get_col("SELECT purity FROM {$wpdb->prefix}diamond_purity
    WHERE purity IN ('14kt','18kt')");
}

// Utility function to get the ring grams % from the database
function get_ring_grams_percentage($ring_size) {
    global $wpdb;
    return $wpdb->get_var($wpdb->prepare("
        SELECT variation_grams FROM {$wpdb->prefix}ring_size WHERE ring_size = %s", $ring_size));
}

// Utility function to get and format the updated price for display
function get_displayed_price_html($price, $product) {
    $args = array('price' => floatval($price));

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

// Utility function to get all required product data (including gold rate)
function get_all_product_data($product, $all = false) {
    $data1 = array('metal_purity' => $product->get_attribute('metal-purity')); // Not for calculation
    $data2 = array(
        'diamond_quality' => $product->get_attribute('diamond-quality'),
        'diamond_sieves'  => $product->get_attribute('sieves'),
        'diamond_weight'  => $product->get_attribute('diamond-weight-ct'),
        'diamond_pieces'  => $product->get_attribute('diamond-pieces'),
        'net_weight'      => $product->get_attribute('net-weight-g'),
        'dft_ring_size'   => $product->get_attribute('default-ring-size'),
        'gross_weight'    => $product->get_attribute('gross-weight'),
        'regular_price'   => $product->get_regular_price(), // Regular price
        'gold_rate'       => get_gold_rate(), // Load the latest gold rate
    );
    return $all ? array_merge($data1, $data2) : $data2;
}

// Remove Woocommerce displayed price
add_action('woocommerce_single_product_summary', 'hide_regular_price_show_updated_price', 1);
function hide_regular_price_show_updated_price() {
    if ( has_term( array('ring', 'rings'), 'product_cat' ) ) {
        remove_action('woocommerce_single_product_summary', 'woocommerce_template_single_price', 10);
    }
}

// Add some custom form fields to single product add to cart form
add_action('woocommerce_before_add_to_cart_button', 'add_to_cart_product_pricing',);
function add_to_cart_product_pricing() {
    global $product;

    // Targeting "ring" or "rings" product category
    if ( is_product()&& has_term(array('ring', 'rings'), 'product_cat') ) {
        // Get necessary product data, converting each element to usable variables (incl gold rate)
        extract(get_all_product_data($product, true));

        // Load data from custom tables for further calculations
        $metal_purity_percent  = get_metal_purity($metal_purity); // Metal Purity percent
        $diamond_shape = get_diamond_shape($diamond_sieves, $diamond_quality); // Get the diamond shape

        // Calculations
        $gold_value    = ($gold_rate * $metal_purity_percent) / 100; // Gold value
        $diamond_total = ($diamond_shape * ($diamond_weight / 5)) * $diamond_pieces; // diamond total
        $calc_price    = round( ($gold_value * $net_weight) + $regular_price + $diamond_total ); // Calculated price

        // Displaying product calculated price and Gross Weight
        printf('<p class="product-price">%s</p>', get_displayed_price_html($calc_price, $product));
        printf('<p class="grossweight">' . __('Weight: %s') . '</p>', wc_format_weight($gross_weight)); 

        echo '<div class="custom-fields">';

        echo '<label for="ring-size">' . __("Ring Size") . ':</label>
        <select id="ring-size" name="ring_size">';

        // Loop through ring sizes
        foreach (get_ring_sizes() as $ring_size) {
            printf( '<option value="%s"%s>%s</option>',$ring_size, selected($ring_size, $def_ring_size), $ring_size );
        }
        echo '</select><br>';

        echo ' <label for="metal-purity">' . __("Metal Purity") . ':</label>
        <select id="metal-purity" name="metal_purity">';

        // Loop through metal purity       
        foreach (get_metal_purity_14k_18k() as $purity) {
            printf( '<option value="%s"%s>%s</option>', $purity, selected($purity, $metal_purity), $purity );
        }
        echo '</select>
        <input type="hidden" id="updated_price" name="updated_price" value="'.$calc_price.'" />
        </div>';
    }
}

// PHP Ajax receiver
add_action( 'wp_ajax_updating_price', 'calculating_price_update' );
add_action( 'wp_ajax_nopriv_updating_price', 'calculating_price_update' );
function calculating_price_update() {
    if ( isset($_POST['product_id']) && isset($_POST['ring_size']) && isset($_POST['metal_purity']) ) {
        $product = wc_get_product( intval($_POST['product_id']) ); // get the Product object

        // Get necessary product data, converting each element to usable variables (incl gold rate)
        extract(get_all_product_data($product));

        $ring_size    = esc_attr($_POST['ring_size']); // Get selected "ring size"
        $metal_purity = esc_attr($_POST['metal_purity']);// Get selected "metal purity"

        // Load data from custom tables for further calculations
        $metal_purity_percent = get_metal_purity($metal_purity); // Metal Purity percentage
        $ring_grams_percent   = get_ring_grams_percentage($ring_size); // size gram variation
        $diamond_shape        = get_diamond_shape($diamond_sieves, $diamond_quality); // diamond shape

        // Pre calculations
        $gold_value    = ($gold_rate * $metal_purity_percent) / 100;  // Calculate gold value
        $diamond_total = ($diamond_shape * ($diamond_weight / 5)) * $diamond_pieces;

        // Get calculated updated price
        if ($def_ring_size < $ring_size) {
            $net_weight_1  = $net_weight + $ring_grams_percent;
            $updated_price = ($gold_value * $net_weight_1) + $regular_price + $diamond_total;
        } elseif ($def_ring_size == $ring_size) {
            $updated_price = ($gold_value * $net_weight) + $regular_price + $diamond_total;
        } else {
            $net_weight_2  = $net_weight - $ring_grams_percent;
            $updated_price = round( ($gold_value * $net_weight_2) + $regular_price + $diamond_total );
        }
        // Send back the updated price data to jQuery
        echo json_encode( array(
            'raw' => $updated_price, 
            'html' => get_displayed_price_html($updated_price, $product) 
        ) );
    }
    wp_die(); // Always Exit silently
}

// Add custom cart item data
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) esc_html($_POST['updated_price']); // Custom calculated price

        if ( isset($_POST['ring_size']) && ! empty($_POST['ring_size']) ) {
            $cart_item_data['ring_size'] = esc_attr($_POST['ring_size']); // Ring size
        }

        if ( isset($_POST['metal_purity']) && ! empty($_POST['metal_purity']) ) {
            $cart_item_data['metal_purity'] = esc_attr($_POST['metal_purity']); // Metal purity
        }
        // Make each item as a unique separated cart item
        $cart_item_data['unique_key'] = md5(microtime() . rand());
    }
    
    return $cart_item_data;
}

// Display cart item calculated price in Mini Cart
add_action('woocommerce_cart_item_price', 'filter_cart_displayed_price', 10, 2);
function filter_cart_displayed_price($price, $cart_item) {
    if ( has_term( array('ring', 'rings'), 'product_cat', $cart_item['product_id'] ) 
    && 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;
}

// Set the calculated price in cart and checkout
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;

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

// Save custom field values as order item metadata and display on orders
add_action( 'woocommerce_checkout_create_order_line_item', 'save_custom_fields_as_order_item_metadata', 10, 4 );
function save_custom_fields_as_order_item_metadata( $item, $cart_item_key, $values, $order ) {
    if( array_key_exists('ring_size', $values) && array_key_exists('metal_purity', $values) ) {
        $item->add_meta_data('ring_size', $values['ring_size']);
        $item->add_meta_data('metal_purity', $values['metal_purity']);
    }
}

// Have a readable "meta key" label name replacementÒÒ
add_filter( 'woocommerce_order_item_display_meta_key', 'filter_order_item_display_meta_key', 10, 3 );
function filter_order_item_display_meta_key( $display_key, $meta, $item ) {
    // only on Admin
    if ( $display_key === 'ring_size' ) {
        $display_key = __('Ring size');
    } elseif ( $display_key === 'metal_purity' ) {
        $display_key = __('Metal purity');
    }
    return $display_key;
}


该代码可用于:

  • 活动子主题(或活动主题)的functions.php文件
  • 在插件。

应该能用

相关问题