1

I need to add three checkout fields in WooCommerce checkout:

  1. 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.

  2. 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.

  1. 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');
        }
    }
}

LoicTheAztec
  • 229,944
  • 23
  • 356
  • 399
Inger
  • 13
  • 5

1 Answers1

0

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 = '&nbsp;<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 = '&nbsp;<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.

LoicTheAztec
  • 229,944
  • 23
  • 356
  • 399
  • Wow, thank you very very much, it works like a charm and I'm so grateful for your help :-) – Inger Jun 20 '23 at 14:17
  • Done! May I ask an additional question, how can I make the marked/answered fields show on backend order and in emails? – Inger Jun 20 '23 at 15:05
  • See [this related threads](https://stackoverflow.com/search?tab=newest&q=user%3a3730754%20woocommerce_checkout_create_order&searchOn=3). Try something, and if you have problems, ask a new question providing related code. – LoicTheAztec Jun 20 '23 at 15:33