英文:
Dynamic calculated custom fees based on custom checkboxes in Woocommerce
问题
我明白你的请求,以下是翻译好的部分:
在WooCommerce使用Avada主题时,我有一个小问题:
我想要显示一个字段一次,即使有多个产品,然后一次计算价格。
以下是Avada主题的review-order.php部分文件:
do_action( 'woocommerce_review_order_before_cart_contents' );
foreach ( WC()->cart->get_cart() as $cart_item_key => $cart_item ) {
$_product = apply_filters( 'woocommerce_cart_item_product', $cart_item['data'], $cart_item, $cart_item_key );
$product_id = apply_filters( 'woocommerce_cart_item_product_id', $cart_item['product_id'], $cart_item, $cart_item_key );
$product_name = apply_filters( 'woocommerce_cart_item_name', $_product->get_name(), $cart_item, $cart_item_key );
// 输出产品名称。
echo '<h4>' . esc_html( $product_name ) . '</h4>';
// 输出liftgate字段。
woocommerce_form_field( 'liftgate_' . $cart_item_key, array(
'type' => 'checkbox',
'class' => array( 'form-row-wide' ),
'label' => 'Add Liftgate ($90)',
), '');
// 输出inside delivery字段。
woocommerce_form_field( 'inside_delivery_' . $cart_item_key, array(
'type' => 'checkbox',
'class' => array( 'form-row-wide' ),
'label' => 'Add Inside Delivery ($135)',
), '');
}
do_action( 'woocommerce_review_order_after_cart_contents' );
这是我主题的functions.php文件中相关的代码:
function calculate_additional_fees( $cart ) {
$liftgate_fee = 90;
$inside_delivery_fee = 135;
$liftgate_total = 0;
$inside_delivery_total = 0;
// 遍历购物车项目
foreach ( $cart->get_cart() as $cart_item_key => $cart_item ) {
if ( isset( $_POST['liftgate_' . $cart_item_key] ) && $_POST['liftgate_' . $cart_item_key] == 1 ) {
$liftgate_total += $liftgate_fee;
}
if ( isset( $_POST['inside_delivery_' . $cart_item_key] ) && $_POST['inside_delivery_' . $cart_item_key] == 1 ) {
$inside_delivery_total += $inside_delivery_fee;
}
}
// 添加liftgate费用
if ( $liftgate_total > 0 ) {
$cart->add_fee( 'Liftgate', $liftgate_total );
}
// 添加inside delivery费用
if ( $inside_delivery_total > 0 ) {
$cart->add_fee( 'Inside Delivery', $inside_delivery_total );
}
}
add_action( 'woocommerce_cart_calculate_fees', 'calculate_additional_fees', 20, 1 );
如何修复这些问题?
英文:
I have a little problem on WooCommerce using Avada theme:
I want to display a field one time, even if there are multiple products, and calculate the price one time.
See the details are below...
Here is Avada theme review-order.php partial file:
<?php
do_action( 'woocommerce_review_order_before_cart_contents' );
foreach ( WC()->cart->get_cart() as $cart_item_key => $cart_item ) {
$_product = apply_filters( 'woocommerce_cart_item_product', $cart_item['data'], $cart_item, $cart_item_key );
$product_id = apply_filters( 'woocommerce_cart_item_product_id', $cart_item['product_id'], $cart_item, $cart_item_key );
$product_name = apply_filters( 'woocommerce_cart_item_name', $_product->get_name(), $cart_item, $cart_item_key );
// Output the product name.
echo '<h4>' . esc_html( $product_name ) . '</h4>';
// Output the liftgate field.
woocommerce_form_field( 'liftgate_' . $cart_item_key, array(
'type' => 'checkbox',
'class' => array( 'form-row-wide' ),
'label' => 'Add Liftgate ($90)',
), '');
// Output the inside delivery field.
woocommerce_form_field( 'inside_delivery_' . $cart_item_key, array(
'type' => 'checkbox',
'class' => array( 'form-row-wide' ),
'label' => 'Add Inside Delivery ($135)',
), '');
}
do_action( 'woocommerce_review_order_after_cart_contents' );
Here is my related code in y theme's functions.php file:
function calculate_additional_fees( $cart ) {
$liftgate_fee = 90;
$inside_delivery_fee = 135;
$liftgate_total = 0;
$inside_delivery_total = 0;
// Loop through cart items
foreach ( $cart->get_cart() as $cart_item_key => $cart_item ) {
if ( isset( $_POST['liftgate_' . $cart_item_key] ) && $_POST['liftgate_' . $cart_item_key] == 1 ) {
$liftgate_total += $liftgate_fee;
}
if ( isset( $_POST['inside_delivery_' . $cart_item_key] ) && $_POST['inside_delivery_' . $cart_item_key] == 1 ) {
$inside_delivery_total += $inside_delivery_fee;
}
}
// Add liftgate fee
if ( $liftgate_total > 0 ) {
$cart->add_fee( 'Liftgate', $liftgate_total );
}
// Add inside delivery fee
if ( $inside_delivery_total > 0 ) {
$cart->add_fee( 'Inside Delivery', $inside_delivery_total );
}
}
add_action( 'woocommerce_cart_calculate_fees', 'calculate_additional_fees', 20, 1 );
How could I fix those issues.
答案1
得分: 0
为允许根据购物车项目计数而触发的两个唯一复选框计算的2个自定义费用,需要使用Ajax和会话变量提供更复杂的功能...
首先,您应该恢复原始的模板文件,从您的Avada主题自定义的review-order.php文件中删除这两个自定义字段。
基于[此类似的主题][1],以下是代码:
// 为包装选择添加自定义单选框字段
add_action( 'woocommerce_review_order_after_shipping', 'checkout_shipping_form_delivery_addition', 20 );
function checkout_shipping_form_delivery_addition(){
$domain = 'woocommerce';
echo '<tr class="delivery-checkbox"><th>' . __('Delivery options (per item)', $domain) . '</th><td>';
// 从WooCommerce会话变量中获取交付选项数据
$delivery_fees = WC()->session->get('delivery_options');
$chosen_liftgate = isset($delivery_fees['liftgate']) && $delivery_fees['liftgate'] ? true : false;
$chosen_ins_delivery = isset($delivery_fees['ins_delivery']) && $delivery_fees['ins_delivery'] ? true : false;
// 输出Liftgate字段
woocommerce_form_field( 'liftgate', array(
'type' => 'checkbox',
'class' => array( 'form-row-wide' ),
'label' => __('Liftgate ($90)', $domain),
), $chosen_liftgate);
// 输出Inside Delivery字段
woocommerce_form_field( 'ins_delivery', array(
'type' => 'checkbox',
'class' => array( 'form-row-wide' ),
'label' => __('Inside Delivery ($135)', $domain),
), $chosen_ins_delivery);
echo '</td></tr>';
}
// PHP:从非必填字段中移除“(可选)”
add_filter( 'woocommerce_form_field' , 'remove_checkout_optional_fields_label', 10, 4 );
function remove_checkout_optional_fields_label( $field, $key, $args, $value ) {
// 仅在结帐页面上
if( is_checkout() && ! is_wc_endpoint_url() && ( 'liftgate' === $key || 'inside_delivery' === $key )) {
$optional = ' <span class="optional">(' . esc_html__( 'optional', 'woocommerce' ) . ')</span>';
$field = str_replace( $optional, '', $field );
}
return $field;
}
// jQuery - Ajax脚本
add_filter( 'wp_footer' , 'checkout_delivery_script' );
function checkout_delivery_script() {
// 仅在结帐页面上
if( ! ( is_checkout() && ! is_wc_endpoint_url() ) ) return;
// WC()->session->__unset('delivery_options'); // 重置'delivery_options'会话变量
$optional = ' <span class="optional">(' . esc_html__( 'optional', 'woocommerce' ) . ')</span>';
?>
<script>
jQuery(function($){
if (typeof wc_checkout_params === 'undefined')
return false;
// 在“更新”结帐表单事件上移除自定义复选框字段中的“(可选)”
$(document.body).on('update_checkout', function(){
$('#liftgate_field label > .optional').remove();
$('#inside_delivery_field label > .optional').remove();
});
// Ajax
$('form.checkout').on('change', '.delivery-checkbox input', function(e){
//e.preventDefault();
var iSchecked = $(this).is(":checked") ? 1 : 0,
fieldKey = e.target['name'];
$.ajax({
type: 'POST',
url: wc_checkout_params.ajax_url,
data: {
'action': 'delivery_options',
'is_checked': iSchecked,
'field_slug': fieldKey,
},
success: function (result) {
$('body').trigger('update_checkout');
console.log(result); // 仅用于测试 | 待移除
},
error: function(error){
console.log(error); // 仅用于测试 | 待移除
}
});
});
});
</script>
<?php
}
// 获取Ajax请求并保存到WC会话中
add_action( 'wp_ajax_delivery_options', 'wc_get_delivery_options_data' );
add_action( 'wp_ajax_nopriv_delivery_options', 'wc_get_delivery_options_data' );
function wc_get_delivery_options_data() {
if ( isset($_POST['is_checked']) && isset($_POST['field_slug']) ){
// 从WooCommerce会话变量中获取交付选项
$delivery_options = WC()->session->get('delivery_options');
// 如果为空,则初始化
if ( empty($delivery_options) ) {
$delivery_options = array( 'liftgate' => 0, 'ins_delivery' => 0 );
}
// 清理数据
$field_slug = sanitize_key( $_POST['field_slug'] );
$is_checked = $_POST['is_checked'] ? '1' : '0';
// 将新数据设置到数据数组中
$delivery_options[$field_slug] = $is_checked;
// 更新交付选项WooCommerce会话变量
WC()->session->set('delivery_options', $delivery_options );
echo json_encode( $delivery_options ); // 返回值给jQuery
}
die();
}
// 动态计算交付选项费用
add_action( 'woocommerce_cart_calculate_fees', 'calculate_additional_fees', 20, 1 );
function calculate_additional_fees( $cart ) {
// 仅在结帐页面上
if( ! ( is_checkout() && ! is_wc_endpoint_url() ) ) return;
// 项目计数
$cart_items_count = count($cart->get_cart()); // 按购物车项目计数
// $cart_items_count = $cart->get_cart_contents_count(); // 按总购物车项目数量计数
// 按项目计算费用
$liftgate_fee = 90;
$inside_delivery_fee = 135;
// 从WooCommerce会话变量中获取交付选项
$delivery_options = WC()->session->get('delivery_options');
// 添加Liftgate费用
if ( isset($delivery_options['liftgate']) && $delivery_options['liftgate'] ) {
$cart->add_fee( __('Liftgate'), $liftgate_fee * $cart_items_count );
}
// 添加Inside Delivery费用
if ( isset($delivery_options['ins_delivery']) && $delivery_options['ins_delivery'] ) {
$cart->add_fee( __('Inside Delivery
<details>
<summary>英文:</summary>
To allow 2 custom fees calculated on cart items count triggered by 2 unique checkboxes, requires something much more complex powered by Ajax and session variables...
First, you should restore the original template file, removing those 2 custom fields from your Avada theme customized *review-order.php* file.
Based [on this similar thread][1] here is the code:
// Add a custom radio fields for packaging selection
add_action( 'woocommerce_review_order_after_shipping', 'checkout_shipping_form_delivery_addition', 20 );
function checkout_shipping_form_delivery_addition(){
$domain = 'wocommerce';
echo '<tr class="delivery-checkbox"><th>' . __('Delivery options (per item)', $domain) . '</th><td>';
// Get delivery options data from WooCommerce Session variable
$delivery_fees = WC()->session->get('delivery_options');
$chosen_liftgate = isset($delivery_fees['liftgate']) && $delivery_fees['liftgate'] ? true : false;
$chosen_ins_delivery = isset($delivery_fees['ins_delivery']) && $delivery_fees['ins_delivery'] ? true : false;
// Output the liftgate field.
woocommerce_form_field( 'liftgate', array(
'type' => 'checkbox',
'class' => array( 'form-row-wide' ),
'label' => __('Liftgate ($90)', $domain),
), $chosen_liftgate);
// Output the inside delivery field.
woocommerce_form_field( 'ins_delivery', array(
'type' => 'checkbox',
'class' => array( 'form-row-wide' ),
'label' => __('Inside Delivery ($135)', $domain),
), $chosen_ins_delivery);
echo '</td></tr>';
}
// PHP: Remove "(optional)" from our non required fields
add_filter( 'woocommerce_form_field' , 'remove_checkout_optional_fields_label', 10, 4 );
function remove_checkout_optional_fields_label( $field, $key, $args, $value ) {
// Only on checkout page
if( is_checkout() && ! is_wc_endpoint_url() && ( 'liftgate' === $key || 'inside_delivery' === $key )) {
$optional = ' <span class="optional">(' . esc_html__( 'optional', 'woocommerce' ) . ')</span>';
$field = str_replace( $optional, '', $field );
}
return $field;
}
// jQuery - Ajax script
add_filter( 'wp_footer' , 'checkout_delivery_script' );
function checkout_delivery_script() {
// Only on checkout page
if( ! ( is_checkout() && ! is_wc_endpoint_url() ) ) return;
// WC()->session->__unset('delivery_options'); // Reset 'delivery_options' session variable
$optional = '&nbsp;<span class="optional">(' . esc_html__( 'optional', 'woocommerce' ) . ')</span>';
?>
<script>
jQuery(function($){
if (typeof wc_checkout_params === 'undefined')
return false;
// On "update" checkout form event Remove "(optional)" from our custom checkbox fields
$(document.body).on('update_checkout', function(){
$('#liftgate_field label > .optional').remove();
$('#inside_delivery_field label > .optional').remove();
});
// Ajax
$('form.checkout').on('change', '.delivery-checkbox input', function(e){
//e.preventDefault();
var iSchecked = $(this).is(":checked") ? 1 : 0,
fieldKey = e.target['name'];
$.ajax({
type: 'POST',
url: wc_checkout_params.ajax_url,
data: {
'action': 'delivery_options',
'is_checked': iSchecked,
'field_slug': fieldKey,
},
success: function (result) {
$('body').trigger('update_checkout');
console.log(result); // just for testing | TO BE REMOVED
},
error: function(error){
console.log(error); // just for testing | TO BE REMOVED
}
});
});
});
</script>
<?php
}
// Get Ajax request and saving to WC session
add_action( 'wp_ajax_delivery_options', 'wc_get_delivery_options_data' );
add_action( 'wp_ajax_nopriv_delivery_options', 'wc_get_delivery_options_data' );
function wc_get_delivery_options_data() {
if ( isset($_POST['is_checked']) && isset($_POST['field_slug']) ){
// Get delivery options from WooCommerce Session variable
$delivery_options = WC()->session->get('delivery_options');
// Initializing if empty
if ( empty($delivery_options) ) {
$delivery_options = array( 'liftgate' => 0, 'ins_delivery' => 0 );
}
// Sanitizing data
$field_slug = sanitize_key( $_POST['field_slug'] );
$is_checked = $_POST['is_checked'] ? '1' : '0';
// Set new data to the data array
$delivery_options[$field_slug] = $is_checked;
// Updating delivery options WooCommerce Session variable
WC()->session->set('delivery_options', $delivery_options );
echo json_encode( $delivery_options ); // Return the value to jQuery
}
die();
}
// Calculate delivery option Fees dynamically
add_action( 'woocommerce_cart_calculate_fees', 'calculate_additional_fees', 20, 1 );
function calculate_additional_fees( $cart ) {
// Only on checkout page
if( ! ( is_checkout() && ! is_wc_endpoint_url() ) ) return;
// Items count
$cart_items_count = count($cart->get_cart()); // count by cart items
// $cart_items_count = $cart->get_cart_contents_count(); // count by total cart items quantity
// Fee costs by item
$liftgate_fee = 90;
$inside_delivery_fee = 135;
// Get delivery options from WooCommerce Session variable
$delivery_options = WC()->session->get('delivery_options');
// Add liftgate fee
if ( isset($delivery_options['liftgate']) && $delivery_options['liftgate'] ) {
$cart->add_fee( __('Liftgate'), $liftgate_fee * $cart_items_count );
}
// Add inside delivery fee
if ( isset($delivery_options['ins_delivery']) && $delivery_options['ins_delivery'] ) {
$cart->add_fee( __('Inside Delivery'), $inside_delivery_fee * $cart_items_count );
}
}
Code goes in functions.php file of your active child theme (or active theme). Tested and works.
[![enter image description here][2]][2]
[1]: https://stackoverflow.com/questions/51558286/dynamic-shipping-fee-based-on-custom-radio-buttons-in-woocommerce/51572051#51572051
[2]: https://i.stack.imgur.com/3qdKn.png
</details>
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论