Add extra packaging options through radio buttons in WooCommerce checkout

830 Views Asked by At

Based on Update fee dynamically based on radio buttons in Woocommerce checkout anser code. I'm trying to make it work with different packaging options on WooCommerce checkout.

The idea is to be able to provide options for gift wrapping, packaging in a bag and so forth.

Problem is, it gives me selectable options but it's all messed up as it is printing out the HTML for the tags and what not.

This is the code I am working with:

add_action( 'woocommerce_form_field_radio', 'gift_bag_none', 20, 4 );
function gift_bag_none( $field, $key, $args, $value ) {
if ( ! empty( $args['options'] ) && is_checkout() ) {
$field = str_replace( '</label><input ', '</label><br><input ', $field );
$field = str_replace( '<label ', '<label style="display:inline;margin-left:8px;" ', $field );
}
return $field;
}

add_action( 'woocommerce_cart_calculate_fees', 'gift_bag_none_fee', 20, 1 );
function gift_bag_none_fee( $cart ) {
if ( is_admin() && ! defined( 'DOING_AJAX' ) ) return;

    $packing_fee = WC()->session->get( 'chosen_packing' );

        if( $packing_fee === 'box' )
            $fee = 29.00;
    
            else if( $packing_fee === 'none' )
            $fee = 0.00;
        
            else if( $packing_fee === 'both' )
        
            $fee = 25.00;
        else
        $fee = 5.00;

    $cart->add_fee( __( 'Packaging Cost', 'woocommerce' ), $fee );
}

add_action( 'woocommerce_review_order_after_shipping', 'checkout_packing_addition', 20 );
function checkout_packing_addition() {

    $domain = 'woocommerce';

    echo '<tr><th>' . __('Packaging Options', $domain) . '</th><td>';

    echo '<tr class="packing-select"><th>' . __('In a bag?<br>Boxed and wrapped as gift?<br><span style="color:red;">Boxed, wrapped and in a bag?</span><br>Or just the product?', $domain) . '</th><td>';

    $chosen = WC()->session->get('chosen_packing');

    $chosen = empty($chosen) ? WC()->checkout->get_value('radio_packing') : $chosen;

    $chosen = empty($chosen) ? 'none' : $chosen;

    woocommerce_form_field( 'radio_packing', array(
    'type' => 'radio',
    'class' => array( 'form-row-wide packing' ),
    'options' => array(
    'bag' => __('Yes, give it to me in a bag for '.wc_price(5.00), $domain),
    'box' => __('Giftbox + Wrapping for '.wc_price(29.00), $domain),
    'both' => __('Wrapped Giftbox in a Bag for '.wc_price(25.00), $domain),
    'none' => __('Just the product at no extra cost '.wc_price(0.00), $domain)
    ),
    'default' => $chosen,
    ), $chosen );
    echo '</td></tr>';
}

add_action( 'wp_footer', 'checkout_packing_script' );
function checkout_packing_script(){ ?>

    <script type="text/javascript">
    jQuery( function($) {

        $('form.checkout').on('change', 'input[name=radio_packing]', function(e){

            e.preventDefault();

            var p = $(this).val();

            $.ajax({

                type: 'POST',

                url: wc_checkout_params.ajax_url,

                data: {
    'action': 'woo_get_ajax_data',
    'packing': p,
    },

        success: function (result) {
    
            $('body').trigger('update_checkout');
    
        },
    
        error: function(error){
        }
    });
    });
    });
</script>
<?php
}

add_action('wp_ajax_woo_get_ajax_data', 'packing_ajax_data');
add_action('wp_ajax_nopriv_woo_get_ajax_data', 'packing_ajax_data');
function packing_ajax_data() {

    if ( isset($_POST['packing']) ){

        $packing = sanitize_key( $_POST['packing'] );

        WC()->session->set('chosen_packing', $packing );

        echo json_encode( $packing );
}
    die();
}
1

There are 1 best solutions below

0
On BEST ANSWER

Updated: 10/2021 - tested in WordPress 5.8.1 & WooCommerce 5.7.1


Your code has some minor mistakes

  • Use add_filter( 'woocommerce_form_field_radio' instead of add_action(..
  • Use strip_tags( wc_price() ) against wc_price()

So you get:

// Customizing WooCommerce radio form field
function filter_woocommerce_form_field_radio( $field, $key, $args, $value ) {   
    // Specific key and apply on checkout page
    if ( ! empty( $args['options'] ) && $key == 'radio_packing' && is_checkout() ) {
        $field = str_replace( '</label><input ', '</label><br><input ', $field );
        $field = str_replace( '<label ', '<label style="display:inline;margin-left:8px;" ', $field );
    }
    
    return $field;
}
add_filter( 'woocommerce_form_field_radio', 'filter_woocommerce_form_field_radio', 20, 4 );

function action_woocommerce_cart_calculate_fees( $cart ) {
    if ( is_admin() && ! defined( 'DOING_AJAX' ) )
        return;
    
    // Dynamic packing fee
    $packing_fee = WC()->session->get( 'chosen_packing' );
    
    // Determine packing fee
    if ( $packing_fee === 'bag' ) {
        $fee = 5.00;
    } else if( $packing_fee === 'box' ) {
        $fee = 29.00;
    } else if( $packing_fee === 'both' ) {
        $fee = 25.00;
    } else {
        $fee = 0.00;
    }
    
    // Add fee: name - amount - taxable 
    $cart->add_fee( __( 'Packaging fee', 'woocommerce' ), $fee, true );
}
add_action( 'woocommerce_cart_calculate_fees', 'action_woocommerce_cart_calculate_fees', 10, 1 );

// Add a custom radio fields for packaging selection
function action_woocommerce_review_order_after_shipping() {
    // Domain
    $domain = 'woocommerce';

    // Output
    echo '<tr class="packing-select"><th>' . __('Packing options', $domain ) . '</th><td>';

    $chosen = WC()->session->get( 'chosen_packing' );

    $chosen = empty( $chosen ) ? WC()->checkout->get_value( 'radio_packing' ) : $chosen;

    $chosen = empty( $chosen ) ? 'none' : $chosen;

    // Add a custom checkbox field
    woocommerce_form_field( 'radio_packing', array(
        'type'      => 'radio',
        'class'     => array( 'form-row-wide packing' ),
        'options'   => array(
            'bag'       => sprintf( __( 'Yes, give it to me in a bag for %s', $domain ), strip_tags( wc_price( 5.00 ) ) ),
            'box'       => sprintf( __( 'Giftbox + Wrapping for %s', $domain ), strip_tags( wc_price( 29.00 ) ) ),
            'both'      => sprintf( __( 'Wrapped Giftbox in a Bag for %s', $domain ), strip_tags( wc_price( 25.00 ) ) ),
            'none'      => sprintf( __( 'Just the product at no extra cost %s', $domain ), strip_tags( wc_price( 0.00 ) ) )
        ),
        'default'   => $chosen,
    ), $chosen );
    
    echo '</td></tr>';
}
add_action( 'woocommerce_review_order_after_shipping', 'action_woocommerce_review_order_after_shipping', 10, 0 );

// jQuery - Ajax script
function action_wp_footer() {
    if ( ! is_checkout() )
        return; // Only checkout page
    ?>
    <script type="text/javascript">
    jQuery( function($){
        $('form.checkout').on('change', 'input[name=radio_packing]', function(e){
            e.preventDefault();
            var p = $(this).val();
            $.ajax({
                type: 'POST',
                url: wc_checkout_params.ajax_url,
                data: {
                    'action': 'woo_get_ajax_data',
                    'packing': p,
                },
                success: function (result) {
                    $('body').trigger('update_checkout');
                    console.log('response: '+result); // just for testing | TO BE REMOVED
                },
                error: function(error){
                    console.log(error); // just for testing | TO BE REMOVED
                }
            });
        });
    });
    </script>
    <?php

}
add_action( 'wp_footer', 'action_wp_footer', 10, 0 );

// Php Ajax (Receiving request and saving to WC session)
function woo_get_ajax_data() {
    if ( isset($_POST['packing']) ){
        $packing = sanitize_key( $_POST['packing'] );
        WC()->session->set('chosen_packing', $packing );
        echo json_encode( $packing );
    }

    die(); // Always at the end (to avoid server error 500)
}
add_action( 'wp_ajax_woo_get_ajax_data', 'woo_get_ajax_data' );
add_action( 'wp_ajax_nopriv_woo_get_ajax_data', 'woo_get_ajax_data' );