英文:
Custom WooCommerce checkout fields interactions adding discounts
问题
- 需要在WooCommerce结账中添加三个结账字段:
1)一个名为“我已经是会员”的复选框。选中此复选框将显示复选框下方的一个字段,用户必须填写他们的会员号,这是一个6位数字。当会员号填写正确时,应将SEK 200,00的折扣应用于结账中的每个产品,并且结账金额应自动重新计算。当选中此复选框时,会员号字段必须是必填的。
2)一个名为“我是会员,但在另一个俱乐部”的复选框。选中此复选框将显示复选框下方的一个字段,用户必须填写他们的会员号,这是一个6位数字。当选中此复选框时,会员号字段必须是必填的。
必须要求选择这两个选项中的一个,不能在未选中其中一个复选框并填写会员号的情况下下订单。不允许同时选择两个框,只允许选择其中一个。如果一个人勾选了框1然后勾选了框2,框1会自动取消勾选,折扣也会被取消。
3)一个名为“我是志愿者”的复选框。选中此复选框将自动对总结账金额应用SEK 100,00的折扣。此选项应可以与其他选项一起使用。
例如,订购了3个产品,框1和框3都被选中(并填写了有效的会员号),总折扣将为SEK 700,00。如果订购了3个产品,框2和框3都被选中,总折扣将为SEK 100,00。如果只有框1被选中,总折扣将为SEK 600,00。
我使用Astra主题,并可以访问functions.php文件。
我已将以下内容添加到functions.php中。SEK 100,00正常工作,其他两个不起作用,没有应用折扣。
(代码部分未翻译)
英文:
I need to add three checkout fields in WooCommerce checkout:
-
A checkbox labelled "I'm already a member". Checking this will display a field below the checkbox where the person must fill in their member number, which is a 6 digit number. When the member number is filled in correctly, a discount of SEK 200,00 should be applied to every product in the checkout and the checkout amount should automatically be recalculated. The member number field must be required/mandatory when this box is checked.
-
A checkbox labelled "I'm a member, but in another club". Checking this will display a field below the checkbox where the person must fill in their member number, which is a 6 digit number. The member number field must be required/mandatory when this box is checked.
It must be required/mandatory to choose one of those two options, it shouldn't be possible to place the order without having checked one of the boxes, having filled their member number. It should not be possible to choose both boxes, only one of them is allowed. If a person checks box1 and then box2, box1 automatically should be unchecked and the discount should be removed.
- A checkbox labelled "I have been a volunteer". Checking this will automatically apply a discount of SEK 100,00 to the total checkout amount. This option should be possible to be used with the other options.
For example, 3 products ordered, both box1 and box 3 are checked (and valid member number is filled in), the total discount will SEK 700,00. If 3 products are ordered, both box2 and box 3 are checked, the total discount will be SEK 100,00. If only box1 is checked, the total discount will be SEK 600,00.
I use the Astra theme and have access to the functions.php file.
I have added this to the functions.php. The SEK 100,00 is working, the other two don't work, no discount is applied.
add_action('woocommerce_review_order_before_submit', 'custom_checkout_fields');
function custom_checkout_fields() {
echo '<div class="woocommerce-additional-fields">';
// Kryssruta 1: Jag är medlem i klubben
woocommerce_form_field('is_member_checkbox', array(
'type' => 'checkbox',
'class' => array('input-checkbox'),
'label' => __('Jag är medlem i klubben'),
), WC()->session->get('is_member_checkbox'));
echo '<div class="is-member-fields" style="display:none;">';
woocommerce_form_field('member_number', array(
'type' => 'text',
'class' => array('input-text'),
'label' => __('Medlemsnummer'),
'placeholder' => __('Fyll i ditt medlemsnummer'),
), WC()->session->get('member_number'));
echo '</div>';
// Kryssruta 2: Jag har hjälpt till ideellt i klubben
woocommerce_form_field('volunteer_checkbox', array(
'type' => 'checkbox',
'class' => array('input-checkbox'),
'label' => __('Jag har hjälpt till ideellt i klubben'),
), WC()->session->get('volunteer_checkbox'));
// Kryssruta 3: Jag är medlem i annan klubb
woocommerce_form_field('other_club_checkbox', array(
'type' => 'checkbox',
'class' => array('input-checkbox'),
'label' => __('Jag är medlem i annan klubb'),
), WC()->session->get('other_club_checkbox'));
echo '<div class="other-club-fields" style="display:none;">';
woocommerce_form_field('other_club_number', array(
'type' => 'text',
'class' => array('input-text'),
'label' => __('Medlemsnummer i annan klubb'),
'placeholder' => __('Fyll i ditt medlemsnummer'),
), WC()->session->get('other_club_number'));
echo '</div>';
echo '</div>';
// JavaScript för att visa/dölja anpassade fält baserat på kryssrutor
?>
<script>
jQuery(document).ready(function($) {
$('#is_member_checkbox').change(function() {
if ($(this).is(':checked')) {
$('.is-member-fields').show();
} else {
$('.is-member-fields').hide();
}
recalculateCart();
});
$('#volunteer_checkbox').change(function() {
recalculateCart();
});
$('#other_club_checkbox').change(function() {
if ($(this).is(':checked')) {
$('.other-club-fields').show();
} else {
$('.other-club-fields').hide();
}
recalculateCart();
});
function recalculateCart() {
$('body').trigger('update_checkout');
}
});
</script>
<?php
}
// Applicera rabatt baserat på medlemsstatus
add_action('woocommerce_cart_calculate_fees', 'custom_apply_discounts');
function custom_apply_discounts($cart) {
if (is_admin() && !defined('DOING_AJAX'))
return;
if (isset($_POST['post_data'])) {
parse_str($_POST['post_data'], $post_data);
} else {
$post_data = $_POST;
}
if (isset($post_data['is_member_checkbox']) && $post_data['is_member_checkbox'] === '1' && !empty($post_data['member_number']) && preg_match('/^\d{6}$/', $post_data['member_number'])) {
$discount_amount = 200;
$cart->add_fee(__('Medlemsrabatt'), -$discount_amount, false);
WC()->session->set('is_member_checkbox', true);
WC()->session->set('member_number', $post_data['member_number']);
} else {
WC()->session->set('is_member_checkbox', false);
WC()->session->set('member_number', '');
}
if (isset($post_data['volunteer_checkbox']) && $post_data['volunteer_checkbox'] === '1') {
$volunteer_discount = 80; // Uppdatera rabattbeloppet här
$cart->add_fee(__('Ideell rabatt'), -$volunteer_discount, false);
WC()->session->set('volunteer_checkbox', true);
} else {
WC()->session->set('volunteer_checkbox', false);
}
if (isset($post_data['other_club_checkbox']) && $post_data['other_club_checkbox'] === '1' && !empty($post_data['other_club_number']) && preg_match('/^\d{6}$/', $post_data['other_club_number'])) {
foreach ($cart->get_fees() as $fee_key => $fee) {
if ($fee->get_name() === 'Medlemsrabatt') {
$cart->remove_fee($fee_key);
break;
}
}
WC()->session->set('other_club_checkbox', true);
WC()->session->set('other_club_number', $post_data['other_club_number']);
} else {
WC()->session->set('other_club_checkbox', false);
WC()->session->set('other_club_number', '');
}
}
// Återställ kryssrutor vid sidan uppdateras
add_action('woocommerce_before_checkout_form', 'custom_reset_session');
function custom_reset_session() {
if (is_checkout() && WC()->session->get('order_awaiting_payment') !== '1') {
WC()->session->set('is_member_checkbox', false);
WC()->session->set('volunteer_checkbox', false);
WC()->session->set('other_club_checkbox', false);
WC()->session->set('member_number', '');
WC()->session->set('other_club_number', '');
}
}
// Validera Nonce för att undvika nonce_failure
add_action('woocommerce_after_checkout_validation', 'custom_validate_nonce');
function custom_validate_nonce($posted_data) {
if (isset($posted_data['is_member_checkbox']) && $posted_data['is_member_checkbox'] === '1') {
if (!isset($posted_data['is_member_checkbox_nonce']) || !wp_verify_nonce($posted_data['is_member_checkbox_nonce'], 'is_member_checkbox_action')) {
wc_add_notice(__('Ogiltig förfrågan. Vänligen uppdatera sidan och försök igen.'), 'error');
}
}
if (isset($posted_data['other_club_checkbox']) && $posted_data['other_club_checkbox'] === '1') {
if (!isset($posted_data['other_club_checkbox_nonce']) || !wp_verify_nonce($posted_data['other_club_checkbox_nonce'], 'other_club_checkbox_action')) {
wc_add_notice(__('Ogiltig förfrågan. Vänligen uppdatera sidan och försök igen.'), 'error');
}
}
}
答案1
得分: 0
以下是您的代码的翻译部分:
有一些错误、问题和遗漏在您的代码中...所以我已经重新检查了您的代码,删除了一些不必要的块,将JavaScript移动到它自己的函数中(将它排队输出到页脚)。
两个相关的折扣现在都具有正确的行为,并按计划工作。
现在结帐自定义字段验证完美无缺,就像您期望的那样。现在,客户将被强制选择您的两个必填选项之一,并正确填写相关的“会员号码”。
当重新计算购物车(选择选项时),相关的“会员号码”可见字段不再隐藏。
// 在提交订单前审查自定义结帐字段
add_action('woocommerce_review_order_before_submit', 'custom_checkout_fields');
function custom_checkout_fields() {
echo '<div class="woocommerce-additional-fields">';
// 复选框1:我是俱乐部会员
woocommerce_form_field('is_member_checkbox', array(
'type' => 'checkbox',
'class' => array('input-checkbox'),
'label' => __('我是俱乐部会员'),
), WC()->session->get('is_member_checkbox'));
echo '<div class="is-member-fields" style="display:none;">';
woocommerce_form_field('member_number', array(
'type' => 'text',
'class' => array('input-text'),
'label' => __('会员号码'),
'placeholder' => __('填写您的会员号码'),
'required' => true, // <== 必填
), WC()->session->get('member_number'));
echo '</div>';
// 复选框2:我在俱乐部志愿服务
woocommerce_form_field('volunteer_checkbox', array(
'type' => 'checkbox',
'class' => array('input-checkbox'),
'label' => __('我在俱乐部志愿服务'),
), WC()->session->get('volunteer_checkbox'));
// 复选框3:我是其他俱乐部会员
woocommerce_form_field('other_club_checkbox', array(
'type' => 'checkbox',
'class' => array('input-checkbox'),
'label' => __('我是其他俱乐部会员'),
), WC()->session->get('other_club_checkbox'));
echo '<div class="other-club-fields" style="display:none;">';
woocommerce_form_field('other_club_number', array(
'type' => 'text',
'class' => array('input-text'),
'label' => __('其他俱乐部会员号码'),
'placeholder' => __('填写您的其他俱乐部会员号码'),
'required' => true, // <== 必填
), WC()->session->get('other_club_number'));
echo '</div>
</div>';
// (将JavaScript移除以在页脚之后排队)
}
// 从一些非必填字段中删除“(可选)”
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() && ( 'is_member_checkbox' === $key || 'other_club_checkbox' === $key )) {
$optional = ' <span class="optional">('.esc_html__('optional', 'woocommerce').')</span>';
$field = str_replace( $optional, '', $field );
}
return $field;
}
// 用于基于复选框显示/隐藏自定义字段的JavaScript
add_filter('woocommerce_after_checkout_form', 'my_checkout_js_script');
function my_checkout_js_script() {
$optional = ' <span class="optional">('.esc_html__('optional', 'woocommerce').')</span>';
ob_start(); // 开始缓冲(而不是显示)
?>
<script>
var isMemberCheckbox = false, isOtherClubCheckbox = false,
memberNumberVal = '', otherClubNumberVal = '',
memberNumberIsFilled = false, otherClubNumberIsFilled = false;
function recalculateCart() {
$('body').trigger('update_checkout');
}
// 结帐表单委托事件
$('form.checkout').on( 'change', '#is_member_checkbox', function() {
if ($(this).is(':checked')) {
$('.is-member-fields').show();
isMemberCheckbox = true;
isOtherClubCheckbox = false;
if ($('#other_club_checkbox').is(':checked')) {
$('#other_club_checkbox').prop('checked', false); // 取消选中复选框
otherClubNumberVal = ''; // 重置变量值
otherClubNumberIsFilled = false;
$('#other_club_number').val(otherClubNumberVal); // 重置字段值
$('.other-club-fields').hide(); // 隐藏字段
}
recalculateCart();
} else {
$('.is-member-fields').hide();
isMemberCheckbox = false;
memberNumberVal = ''; // 重置变量值
memberNumberIsFilled = false;
$('#member_number').val(memberNumberVal); // 重置字段值
recalculateCart();
}
}).on('mouseleave blur', '.is-member-fields', function() {
memberNumberVal = $('#member_number').val();
if ( ! memberNumberIsFilled && memberNumberVal != '' ) {
recalculateCart();
memberNumberIsFilled = true;
}
}).on( 'change', '#volunteer_checkbox', function() {
recalculateCart();
}).on( 'change', '#other_club_checkbox', function() {
if ($(this).is(':checked')) {
$('.other-club-fields').show();
isOtherClubCheckbox = true;
isMemberCheckbox = false;
if ($('#is_member_checkbox').is(':checked')) {
$('#is_member_checkbox').prop('checked', false); // 取消选中复选框
memberNumberVal = '';
memberNumberIsFilled = false
$('#member_number').val(memberNumberVal); // 重置字段值
$('.is-member-fields').hide();
}
recalculateCart();
} else {
$('.other-club-fields').hide();
isOtherClubCheckbox = false;
otherClubNumberVal = '';
otherClubNumberIsFilled = false;
$('#other_club_number').val(otherClubNumberVal); // 重置字段值
<details>
<summary>英文:</summary>
There were some mistakes, errors and missing things in your code… So I have revisited your code everywhere, removing some unnecessary blocks, moved the JavaScript to its own function (queuing it to be output in the footer).
Both related discounts have now the correct behavior, and work as planed.
The checkout custom field validation is now working perfectly, just as you expect. Now customers will be obliged to choose one of your 2 mmandatory options, and to fill up correctly the related "member numbers".
When the cart is recalculated (when chosing an option), the related "member number" visible field is not hidden anymore.
// Custom checkput fields in review order before submit
add_action('woocommerce_review_order_before_submit', 'custom_checkout_fields');
function custom_checkout_fields() {
echo '<div class="woocommerce-additional-fields">';
// Kryssruta 1: Jag är medlem i klubben
woocommerce_form_field('is_member_checkbox', array(
'type' => 'checkbox',
'class' => array('input-checkbox'),
'label' => __('Jag är medlem i klubben'),
), WC()->session->get('is_member_checkbox') );
echo '<div class="is-member-fields" style="display:none;">';
woocommerce_form_field('member_number', array(
'type' => 'text',
'class' => array('input-text'),
'label' => __('Medlemsnummer'),
'placeholder' => __('Fyll i ditt medlemsnummer'),
'required' => true, // <== Required
), WC()->session->get('member_number') );
echo '</div>';
// Kryssruta 2: Jag har hjälpt till ideellt i klubben
woocommerce_form_field('volunteer_checkbox', array(
'type' => 'checkbox',
'class' => array('input-checkbox'),
'label' => __('Jag har hjälpt till ideellt i klubben'),
), WC()->session->get('volunteer_checkbox'));
// Kryssruta 3: Jag är medlem i annan klubb
woocommerce_form_field('other_club_checkbox', array(
'type' => 'checkbox',
'class' => array('input-checkbox'),
'label' => __('Jag är medlem i annan klubb'),
), WC()->session->get('other_club_checkbox'));
echo '<div class="other-club-fields" style="display:none;">';
woocommerce_form_field('other_club_number', array(
'type' => 'text',
'class' => array('input-text'),
'label' => __('Medlemsnummer i annan klubb'),
'placeholder' => __('Fyll i ditt medlemsnummer'),
'required' => true, // <== Required
), WC()->session->get('other_club_number'));
echo '</div>
</div>';
// (removed javascript to queue it after the footer)
}
// Remove "(optional)" from some 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() && ( 'is_member_checkbox' === $key || 'other_club_checkbox' === $key )) {
$optional = ' <span class="optional">(' . esc_html__( 'optional', 'woocommerce' ) . ')</span>';
$field = str_replace( $optional, '', $field );
}
return $field;
}
// JavaScript för att visa/dölja anpassade fält baserat på kryssrutor
add_filter( 'woocommerce_after_checkout_form' , 'my_checkout_js_script' );
function my_checkout_js_script() {
$optional = ' <span class="optional">(' . esc_html__( 'optional', 'woocommerce' ) . ')</span>';
ob_start(); // Start buffering (instead of displaying)
?>
<script>
var isMemberCheckbox = false, isOtherClubCheckbox = false,
memberNumberVal = '', otherClubNumberVal = '',
memberNumberIsFilled = false, otherClubNumberIsFilled = false;
function recalculateCart() {
$('body').trigger('update_checkout');
}
// Checkout form delegated events
$('form.checkout').on( 'change', '#is_member_checkbox', function() {
if ($(this).is(':checked')) {
$('.is-member-fields').show();
isMemberCheckbox = true;
isOtherClubCheckbox = false;
if ($('#other_club_checkbox').is(':checked')) {
$('#other_club_checkbox').prop('checked', false); // uncheck checkbox
otherClubNumberVal = ''; // reset variable value
otherClubNumberIsFilled = false;
$('#other_club_number').val(otherClubNumberVal); // reset field value
$('.other-club-fields').hide(); // Hide fied
}
recalculateCart();
} else {
$('.is-member-fields').hide();
isMemberCheckbox = false;
memberNumberVal = ''; // reset variable value
memberNumberIsFilled = false;
$('#member_number').val(memberNumberVal); // reset the field value
recalculateCart();
}
}).on('mouseleave blur', '.is-member-fields', function() {
memberNumberVal = $('#member_number').val();
if ( ! memberNumberIsFilled && memberNumberVal != '' ) {
recalculateCart();
memberNumberIsFilled = true;
}
}).on( 'change', '#volunteer_checkbox', function() {
recalculateCart();
}).on( 'change', '#other_club_checkbox', function() {
if ($(this).is(':checked')) {
$('.other-club-fields').show();
isOtherClubCheckbox = true;
isMemberCheckbox = false;
if ($('#is_member_checkbox').is(':checked')) {
$('#is_member_checkbox').prop('checked', false); // uncheck checkbox
memberNumberVal = '';
memberNumberIsFilled = false
$('#member_number').val(memberNumberVal); // reset field value
$('.is-member-fields').hide();
}
recalculateCart();
} else {
$('.other-club-fields').hide();
isOtherClubCheckbox = false;
otherClubNumberVal = '';
otherClubNumberIsFilled = false;
$('#other_club_number').val(otherClubNumberVal); // reset the field value
recalculateCart();
}
}).on('mouseleave blur', '#other_club_number', function() {
otherClubNumberVal = $('#other_club_number').val();
if ( ! otherClubNumberIsFilled && otherClubNumberVal != '' ) {
recalculateCart();
otherClubNumberIsFilled = true;
}
});
// Document body delegated events
$('body').on( 'updated_checkout', function() {
if ( isMemberCheckbox ) {
if ( ! $('#is_member_checkbox').is(':checked') ) {
$('#is_member_checkbox').prop('checked', true);
}
$('.is-member-fields').show();
}
if ( isOtherClubCheckbox ) {
if ( ! $('#other_club_checkbox').is(':checked') ) {
$('#other_club_checkbox').prop('checked', true);
}
$('.other-club-fields').show();
}
}).on('update_checkout', function(){
// On "update" checkout form event Remove "(optional)" from some custom checkbox fields
$('#is_member_checkbox_field label > .optional').remove();
$('#other_club_checkbox_field label > .optional').remove();
});
</script>
<?php
$js_code = ob_get_clean(); // Set the buffered content in a variable
$js_code = str_replace( ['<script>', '</script>'], ['', ''], $js_code ); // Removing some html tags
wc_enqueue_js($js_code); // Queue this JavaScript code to be output in the footer
}
// Applicera rabatt baserat på medlemsstatus
add_action('woocommerce_cart_calculate_fees', 'custom_apply_discounts');
function custom_apply_discounts($cart) {
if (is_admin() && !defined('DOING_AJAX'))
return;
if (isset($_POST['post_data'])) {
parse_str($_POST['post_data'], $post_data);
} else {
$post_data = $_POST;
}
if (isset($post_data['is_member_checkbox']) && $post_data['is_member_checkbox'] === '1' && isset($post_data['member_number']) && preg_match('/^\d{6}$/', $post_data['member_number'])) {
$discount_by_item = 200; // Discount by item quantity
$number_of_items = $cart->get_cart_contents_count();
$discount_amount = $discount_by_item * $number_of_items;
$cart->add_fee(__('Medlemsrabatt'), -$discount_amount, false);
WC()->session->set('is_member_checkbox', true);
WC()->session->set('member_number', $post_data['member_number']);
} else {
WC()->session->set('is_member_checkbox', false);
WC()->session->set('member_number', '');
}
if (isset($post_data['volunteer_checkbox']) && $post_data['volunteer_checkbox'] === '1') {
$volunteer_discount = 80; // Uppdatera rabattbeloppet här
$cart->add_fee(__('Ideell rabatt'), -$volunteer_discount, false);
WC()->session->set('volunteer_checkbox', true);
} else {
WC()->session->set('volunteer_checkbox', false);
}
if (isset($post_data['other_club_checkbox']) && $post_data['other_club_checkbox'] === '1' && !empty($post_data['other_club_number']) && preg_match('/^\d{6}$/', $post_data['other_club_number'])) {
WC()->session->set('other_club_checkbox', true);
WC()->session->set('other_club_number', $post_data['other_club_number']);
} else {
WC()->session->set('other_club_checkbox', false);
WC()->session->set('other_club_number', '');
}
}
// Återställ kryssrutor vid sidan uppdateras
add_action('woocommerce_before_checkout_form', 'custom_reset_session');
function custom_reset_session() {
if (is_checkout() && WC()->session->get('order_awaiting_payment') !== '1') {
WC()->session->set('is_member_checkbox', false);
WC()->session->set('volunteer_checkbox', false);
WC()->session->set('other_club_checkbox', false);
WC()->session->set('member_number', '');
WC()->session->set('other_club_number', '');
}
}
// Custom checkout fields validation
add_action('woocommerce_checkout_process', 'custom_checkout_field_validation');
function custom_checkout_field_validation() {
$member_club_cb = isset($_POST['is_member_checkbox']) && $_POST['is_member_checkbox'] === '1';
$other_club_cb = isset($_POST['other_club_checkbox']) && $_POST['other_club_checkbox'] === '1';
if ( ! ( $member_club_cb || $other_club_cb ) ) {
wc_add_notice(__('Choose between "is_member_checkbox" or "other_club_checkbox" required options'), 'error');
}
if ( $member_club_cb && isset($_POST['member_number']) ) {
if ( $member_club_cb && isset($_POST['member_number']) && empty($_POST['member_number']) ) {
wc_add_notice( __('Please fill in the "Member number" field.'), 'error');
}
elseif ( 1 !== preg_match('/^\d{6}$/', $_POST['member_number']) ) {
wc_add_notice( __('Please fill in the "Member number" field with a correct number.'), 'error');
}
}
if ( $other_club_cb && isset($_POST['other_club_number']) ) {
if ( empty($_POST['other_club_number']) ) {
wc_add_notice( __('Please fill in the "Other Club number" field.'), 'error');
}
elseif ( 1 !== preg_match('/^\d{6}$/', $_POST['other_club_number']) ) {
wc_add_notice( __('Please fill in the "Other Club number" field with a correct number.'), 'error');
}
}
}
Code goes in functions.php file of your active child theme (or active theme). Tested and works.
</details>
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论