根据 WooCommerce 中的自定义结帐单选按钮和文本字段设置动态费用
Posted
技术标签:
【中文标题】根据 WooCommerce 中的自定义结帐单选按钮和文本字段设置动态费用【英文标题】:Set a dynamic fee based on custom checkout radio buttons and text field in WooCommerce 【发布时间】:2021-05-16 11:28:27 【问题描述】:我正在尝试创建一个自定义结帐单选按钮,以百分比计算餐厅小费。
对于单选按钮,静态值工作正常。
但是,我想获取小计并计算自定义单选按钮点击的特定百分比。
这是我的代码
add_action( 'woocommerce_after_checkout_billing_form', 'add_box_option_to_checkout' );
function add_box_option_to_checkout( $checkout )
$chosen = WC()->session->get( 'tip' );
$chosen = empty( $chosen ) ? WC()->checkout->get_value( 'tip' ) : $chosen;
$chosen = empty( $chosen ) ? '0' : $chosen;
$total = WC()->cart->get_subtotal();
$fivetip = $total * 0.05;
woocommerce_form_field( 'tip', array(
'type' => 'radio',
'class' => array( 'form-row-wide', 'update_totals_on_change' ),
'options' => array(
$fivetip => '5%',
'10.00' => '10%',
'15.00' => '15%',
),
), $chosen );
woocommerce_form_field( 'add_tip', array(
'type' => 'text',
'class' => array('add_tipform-row-wide'),
'placeholder' => __('Enter Custom Tip Amount')
), $checkout->get_value( 'add_tip' ));
add_action( 'woocommerce_cart_calculate_fees', 'checkout_tip_fee', 20, 1 );
function checkout_tip_fee( $cart )
if ( $radio = WC()->session->get( 'tip' ) )
$cart->add_fee( 'Tip', $radio );
add_action( 'woocommerce_checkout_update_order_review', 'checkout_tip_choice_to_session' );
function checkout_tip_choice_to_session( $posted_data )
parse_str( $posted_data, $output );
if ( isset( $output['tip'] ) )
WC()->session->set( 'tip', $output['tip'] );
【问题讨论】:
【参考方案1】:以下是使用 Ajax 和 WC 会话的高级功能:
它将根据选定的单选按钮选项添加自定义提示(作为自定义费用):固定百分比选项或自定义选项,将显示文本字段以允许客户输入固定金额。
显示的字段是手动编码的,以便比 WooCommerce 表单字段更好地显示单选按钮(请参阅下面的屏幕截图)。
它对客户的作用:
在结帐页面加载时,将应用 5% 的小费(收费)(默认选择)。将所选选项更改为其他选项时,应用的费用会发生变化。
如果选择了“自定义”选项,则会在下方显示文本字段时移除费用:
客户可以输入固定金额,然后根据该金额应用提示(费用)。
代码如下:
// Display custom checkout fields
add_action( 'woocommerce_after_checkout_billing_form', 'add_box_option_to_checkout' );
function add_box_option_to_checkout( )
// Here set your radio button options (Values / Labels pairs)
$options = array( '5' => '5%', '10' => '10%', '15' => '15%', 'custom' => __('Custom', 'woocommerce') );
// Radio button fields
echo '<style> #add_tip_field.form-row label display:inline-block; margin-left:6px; </style>
<p class="form-row form-row-wide" id="add_tip_field"><span class="woocommerce-input-wrapper">
<label for="add_tip"><strong>'.__('Add a tip', 'woocommerce'). ':</strong> </label>';
foreach ( $options as $value => $label_name )
$checked = $value == '5' ? ' checked="checked"' : '';
echo '<label for="add_tip_'.$value.'" class="radio ">
<input type="radio" class="input-radio " value="'.$value.'" name="add_tip" id="add_tip_'.$value.'"'.$checked.'> '.$label_name.'
</label>';
echo '</span></p>';
// Text field (hidden by default)
echo '<p class="form-row form-row-wide" id="custom_tip_field" style="display:none""><span class="woocommerce-input-wrapper">
<input type="text" class="input-text " name="custom_tip" id="custom_tip" value="" placeholder="'.__('Input a tip amount', 'woocommerce').'">
</span></p>';
// jQuery / Ajax script
add_action( 'woocommerce_after_checkout_form', 'wc_checkout_fee_script' );
function wc_checkout_fee_script()
?>
<script type="text/javascript">
jQuery( function($)
if (typeof wc_checkout_params === 'undefined')
return false;
var addTip = 'input[name="add_tip"]',
customTip = 'input[name="custom_tip"]'
function triggerAjaxEvent( amount, type = 'percent' )
$.ajax(
type: 'POST',
url: wc_checkout_params.ajax_url,
data:
'action': 'tip_fee',
'amount': amount,
'type' : type
,
success: function (result)
$(document.body).trigger('update_checkout');
console.log(result);
,
);
triggerAjaxEvent( $(addTip+':checked').val() );
$('form.checkout').on('change', addTip, function()
var textField = $('#custom_tip_field'),
percent = $(this).val();
if( percent === 'custom' && textField.css('display') === 'none' )
textField.show(200);
else if ( percent !== 'custom' && textField.css('display') !== 'none' )
textField.hide(200, function()
$(customTip).val('');
);
triggerAjaxEvent( percent );
);
$('form.checkout').on('input change', customTip, function()
triggerAjaxEvent( $(this).val(), 'custom' );
);
);
</script>
<?php
// Get Ajax request and save data to WC session
add_action( 'wp_ajax_tip_fee', 'get_tip_fee' );
add_action( 'wp_ajax_nopriv_tip_fee', 'get_tip_fee' );
function get_tip_fee()
if ( isset($_POST['amount']) && isset($_POST['type']) )
$fee = is_numeric($_POST['amount']) && $_POST['amount'] > 0 ? floatval($_POST['amount']) : 0;
WC()->session->set('fee_data', array(
'type' => esc_attr($_POST['type']),
'amount' => $fee
) );
print_r(WC()->session->get('fee_data'));
die();
// Add a dynamic fee from WC Session ajax data
add_action( 'woocommerce_cart_calculate_fees', 'checkout_custom_tip_fee' );
function checkout_custom_tip_fee( $cart )
if ( is_admin() && !defined('DOING_AJAX') )
return;
$data = WC()->session->get('fee_data');
$fee = $total = 0;
if ( isset($data['type']) && isset($data['amount']) )
// 1. Fixed Fee amount
if ( $data['type'] === 'custom' )
$text = $data['type'];
$fee = $data['amount'];
// 2. Calculated percentage Fee amount
elseif ( $data['type'] === 'percent' && $data['amount'] > 0 )
$text = $data['amount'] . '%';
// Get cart subtotal excl. Taxes (discounted)
foreach ( $cart->get_cart() as $cart_item )
$total = $cart_item['line_total'];
// Calculate fee
$fee = $total * $data['amount'] / 100 ;
// Add the fee
if ( $fee > 0 )
$cart->add_fee( sprintf( __('Tip (%s)', 'woocommerce' ), $text ), $fee );
代码进入活动子主题(或活动主题)的functions.php 文件中。经过测试并且可以工作。
与您的评论相关的补充:
要在最后一个函数中使用购物车项目总计 including
税金替换:
// Get cart subtotal excl. Taxes (discounted)
foreach ( $cart->get_cart() as $cart_item )
$total = $cart_item['line_total'];
与
// Get cart subtotal Incl. Taxes (discounted)
foreach ( $cart->get_cart() as $cart_item )
$total = $cart_item['line_total'] + $cart_item['line_tax'];
【讨论】:
我添加了一个值 0,以便默认情况下不检查任何内容。自定义费用目前不起作用。单选按钮按预期工作。非常感谢您的时间和精力。对我来说意义重大。我无法弄清楚为什么输入字段中的值不起作用。它对你有用吗? 我也修复了文本字段。此代码中的自定义必须是小写字母。 ` if ( $data['type'] === 'custom' ) ` 非常感谢你帮助我。没有您的帮助,这是不可能的。 我遇到了问题。如果用户返回在线订单并添加更多商品,则 woocommerce 会话会给出错误的计算。看起来,必须为提示取消设置 woocommerce 会话值,因为当页面加载时,它会被存储并显示在结帐页面右侧的购物车中。但我不知道该怎么做以及在哪里添加代码。请帮帮我 谢谢。它有效,但小费百分比不正确。这是link。只有带有文本框的那个才能完美运行。问题出在单选按钮上。 我不知道'
在哪里。我刚刚用你的代码替换了我的代码,但单选按钮的小费百分比仍然不正确。没关系,你不用说对不起。你给了我你的时间和支持,这很多。稍后我会清理 cmets 并为您的答案投票,因为这个问题是从我的其他帐户发布的。【参考方案2】:
你可以这样得到:
-
添加字段进行结帐
清空/取消选择基于字段值的字段(以便仅保留单选按钮或文本字段值)
根据字段计算费用并将费用添加到购物车
所以:
// add custom fields to checkout
add_action( 'woocommerce_after_checkout_billing_form', 'add_box_option_to_checkout' );
function add_box_option_to_checkout( $checkout )
woocommerce_form_field( 'tip', array(
'type' => 'radio',
'class' => array( 'form-row-wide', 'update_totals_on_change' ),
'options' => array(
'5' => '5%',
'10' => '10%',
'15' => '15%',
),
));
woocommerce_form_field( 'add_tip', array(
'type' => 'text',
'class' => array('add_tipform-row-wide', 'update_totals_on_change'),
'placeholder' => __('Enter Custom Tip Amount')
));
现在,jQuery脚本将在选择单选按钮时清空文本字段,反之亦然:
// uncheck radio buttons when text field is changed
add_action( 'wp_footer', 'uncheck_radio_buttons_when_text_field_is_changed' );
function uncheck_radio_buttons_when_text_field_is_changed()
if ( is_checkout() && ! is_wc_endpoint_url() )
?>
<script type="text/javascript">
// deselect radio buttons when an amount is entered in the text field
jQuery('#add_tip').keyup(function()
jQuery('#tip_field input[name=tip]').prop('checked', false);
);
// clears the text field when a percentage is selected
jQuery('input[name=tip]').change(function()
jQuery('#add_tip').val('');
);
</script>
<?php
最后它根据购物车的小计 (不含税)所选择的值计算费用金额。
确保您使用相同的费用名称添加到购物车 为了覆盖相同的内容并只显示一个。
// adds a custom fee based on the field valued
add_action( 'woocommerce_cart_calculate_fees', 'add_custom_fee', 10, 1 );
function add_custom_fee( $cart )
// get the subtotal (excluding taxes)
$subtotal = WC()->cart->subtotal_ex_tax;
if ( ! $_POST || is_admin() || ! is_ajax() )
return;
if ( isset( $_POST['post_data'] ) )
parse_str( $_POST['post_data'], $post_data );
else
$post_data = $_POST;
// adds the fee based on the checked percentage
if ( isset( $post_data['tip'] ) )
$percentage = $post_data['tip'];
$fee = $subtotal * $percentage / 100;
if ( $fee > 0 )
WC()->cart->add_fee( 'Tip', $fee, true );
// adds the fee based on the amount entered
if ( isset( $post_data['add_tip'] ) )
$fee = (float) str_replace( ',', '.', $post_data['add_tip'] );
if ( $fee > 0 )
WC()->cart->add_fee( 'Tip', $fee, true );
代码已经过测试并且可以运行。将其添加到活动主题的 functions.php 中。
【讨论】:
非常感谢您的时间和精力。代码按预期工作。以上是关于根据 WooCommerce 中的自定义结帐单选按钮和文本字段设置动态费用的主要内容,如果未能解决你的问题,请参考以下文章
根据 WooCommerce 中的自定义字段值将文本添加到订单摘要
WooCommerce 结帐单选按钮,可根据特定项目小计设置百分比费用
Woocommerce 3中的自定义结帐字段和运输方式ajax交互