Show additional information depending on shipping selected - php

I would like to show additional information/order notes when a specific shipping method was selected.
I have multiple shipping options and when selecting a specific one I need the user to provide a different address in the note, please see the images below:
These are the available shipping options:
I want to show this (and it has to be a required field)
I have seen this answer where a checkbox is used to show/hide the notes of an order on the checkout page:
By doing the following:
add_filter( 'woocommerce_checkout_fields', 'custom_checkout_order_notes' );
function custom_checkout_order_notes( $fields ) {
$fields['order']['order_comments']['class'][] = 'off';
return $fields;
}
add_action( 'woocommerce_before_order_notes', 'checkout_checkbox_show_hide_order_notes' );
function checkout_checkbox_show_hide_order_notes( $fields ) {
$target_id = 'order_comments';
?>
<style> p#<?php echo $target_id; ?>_field.off { display:none;}</style>
<script type="text/javascript">
jQuery(function($){
var a = 'input#checkbox_trigger', b = '#<?php echo $target_id; ?>_field';
$(b).hide('fast');
$(a).change(function(){
if( $(b).hasClass('off') ) {
$(b).removeClass('off');
}
if ( $(this).prop('checked') ) {
$(b).show('fast');
} else {
$(b).hide('fast', function(){
$(b+' input').val('');
});
}
});
});
</script>
<?php
woocommerce_form_field( 'checkbox_trigger', array(
'type' => 'checkbox',
'label' => __('Add a note to your order?', 'woocommerce'),
'class' => array('form-row-wide'),
'clear' => true,
), false );
}
But this is not what I want as described above.
Any help would greatly be appreciated.

I figured it out. I have added comments to help future readers.
add_action( 'woocommerce_billing_fields','woocommerce_check_if_shipping_changed' );
function woocommerce_check_if_shipping_changed() {
global $woocommerce;
if ( is_admin() && ! defined( 'DOING_AJAX' ) )
return;
// Get the selected shipping method
$chosen_methods = WC()->session->get( 'chosen_shipping_methods' );
$chosen_shipping = $chosen_methods[0];
// Check if it is one of the two I want to show "Aditional Information" for (using their ID's)
// I used developer tools to get their ID's
if ($chosen_shipping == 'wbs:6:5977f58e_postnet_to_postnet' || $chosen_shipping == 'wbs:6:014e3dff_pudo_locker') {
if ($chosen_shipping == 'wbs:6:014e3dff_pudo_locker'){
// Change additional notes label to : Pudo Locker Address:
add_filter('woocommerce_checkout_fields', 'make_order_label_pudo', 9999, 1);
}
if ($chosen_shipping == 'wbs:6:5977f58e_postnet_to_postnet'){
// Change additional notes label to : PostNet Address:
add_filter('woocommerce_checkout_fields', 'make_order_label_postnet', 9999, 1);
}
// Show order notes
add_filter( 'woocommerce_enable_order_notes_field', '__return_true', 9999 );
// Make order notes required
add_filter('woocommerce_checkout_fields', 'make_order_notes_required_field', 9999, 1);
}else{
// Hide order notes
add_filter( 'woocommerce_enable_order_notes_field', '__return_false', 9999 );
// Make order notes not a requirement
add_filter('woocommerce_checkout_fields', 'make_order_notes_not_required_field', 9999, 1);
}
}
function make_order_label_pudo( $fields ) {
$fields['order']['order_comments']['label'] = 'Pudo Locker Address:';
return $fields;
}
function make_order_label_postnet( $fields ) {
$fields['order']['order_comments']['label'] = 'PostNet Address:';
return $fields;
}
function make_order_notes_required_field( $fields ) {
$fields['order']['order_comments']['required'] = true;
return $fields;
}
function make_order_notes_not_required_field( $fields ) {
$fields['order']['order_comments']['required'] = false;
return $fields;
}
// The page needs to be refreshed of the changes to apply
add_action( 'wp_footer', 'checkout_shipping_refresh' );
function checkout_shipping_refresh() {
if ( is_checkout() && ! is_wc_endpoint_url() ) :
?><script type="text/javascript">
jQuery( function($){
let isRefreshPage = false;
$('form.checkout').on('change','input[name^="shipping_method"]',function() {
const val = $( this ).val();
isRefreshPage = true;
});
$('body').on('updated_checkout', function(){
if (isRefreshPage) {
location.reload();
}
});
});
</script>
<?php
endif;
}

Related

Checkout input text field that set a discount in WooCommerce

I am using Checkbox field that add / remove a custom fee in WooCommerce answer code which is working perfectly on my shop, to set a discount (a negative fee).
But I want to set the fee amount using an input field. My goal is to reduce the total amount of purchases by the inputed value in a num/text input field. I don't want to use checkbox, I want to use input or number filed for determine amount of the fee.
Is it possible ? How can i do this?
To enable a checkout input text field that set a custom discount in WooCommerce, few changes are required as follows:
// Display an input text field after billing fields
add_action( 'woocommerce_after_checkout_billing_form', 'add_custom_checkout_text_field', 20 );
function add_custom_checkout_text_field(){
woocommerce_form_field( 'custom_discount', array(
'type' => 'text',
'label' => __('Add a discount amount'),
'class' => array( 'form-row-wide' ),
), WC()->session->get('custom_discount') );
}
// Remove "(optional)" label on checkbox field
add_filter( 'woocommerce_form_field' , 'remove_order_comments_optional_fields_label', 10, 4 );
function remove_order_comments_optional_fields_label( $field, $key, $args, $value ) {
// Only on checkout page for Order notes field
if( 'custom_discount' === $key && is_checkout() ) {
$optional = ' <span class="optional">(' . esc_html__( 'optional', 'woocommerce' ) . ')</span>';
$field = str_replace( $optional, '', $field );
}
return $field;
}
// Ajax / jQuery script
add_action( 'wp_footer', 'custom_discount_script' );
function custom_discount_script() {
// On checkoutpage
if( ( is_checkout() && ! is_wc_endpoint_url() ) ) :
?>
<script type="text/javascript">
jQuery( function($){
if (typeof woocommerce_params === 'undefined')
return false;
$(document.body).on('input change', 'input[name=custom_discount]', function(){
$.ajax({
type: 'POST',
url: woocommerce_params.ajax_url,
data: {
'action': 'custom_discount',
'custom_discount': $(this).val(),
},
success: function (result) {
$('body').trigger('update_checkout');
console.log(result);
},
});
});
});
</script>
<?php
endif;
}
// Get the ajax request and set value to WC session
add_action( 'wp_ajax_custom_discount', 'get_ajax_custom_discount' );
add_action( 'wp_ajax_nopriv_custom_discount', 'get_ajax_custom_discount' );
function get_ajax_custom_discount() {
if ( isset($_POST['custom_discount']) ) {
$discount = $_POST['custom_discount'] ? floatval($_POST['custom_discount']) : '';
WC()->session->set('custom_discount', $discount );
// echo WC()->session->get('custom_discount');
}
die();
}
// Add / Remove a custom discount
add_action( 'woocommerce_cart_calculate_fees', 'add_remove_custom_discount', 10, 1 );
function add_remove_custom_discount( $cart ) {
// Only on checkout
if ( ( is_admin() && ! defined( 'DOING_AJAX' ) ) || is_cart() )
return;
$discount = (float) WC()->session->get('custom_discount');
if( $discount > 0 ) {
$cart->add_fee( __( 'Custom Discount', 'woocommerce'), -$discount );
}
}
// Reset WC Session custom discount variable
add_action( 'woocommerce_checkout_order_created', 'reset_wc_session_custom_discount_variable' );
function reset_wc_session_custom_discount_variable( $order ) {
if ( WC()->session->__isset('custom_discount') ) {
WC()->session->__unset('custom_discount');
}
}
Code goes in functions.php file of the active child theme (or active theme). Tested and works.

Ajax Add to cart for simple and variable products on WooCommerce single products

The code below is working for add to cart with WooCommerce for simple products, but not for variable products. Can someone help me out? Because this code works with the latest WC, please do not remove this question because there are lots of codes for this online that do not work at all.
The error I am getting that is says in a notice that I should choose a product option, even when I chose one.
JS:
jQuery(function($) {
$('form.cart').on('submit', function(e) {
e.preventDefault();
var form = $(this);
form.block({ message: null, overlayCSS: { background: '#fff', opacity: 0.6 } });
var formData = new FormData(form.context);
formData.append('add-to-cart', form.find('[name=add-to-cart]').val() );
var $thisbutton = form.find('.single_add_to_cart_button'); //
// Ajax action
$.ajax({
url: wc_add_to_cart_params.wc_ajax_url.toString().replace( '%%endpoint%%', 'ace_add_to_cart' ),
data: formData,
type: 'POST',
processData: false,
contentType: false,
beforeSend: function (response) {
$thisbutton.removeClass('added').addClass('loading');
},
complete: function( response ) {
response = response.responseJSON;
if ( ! response ) {
return;
}
if ( response.error && response.product_url ) {
window.location = response.product_url;
return;
}
// Redirect to cart option
if ( wc_add_to_cart_params.cart_redirect_after_add === 'yes' ) {
window.location = wc_add_to_cart_params.cart_url;
return;
}
// Trigger event so themes can refresh other areas.
$( document.body ).trigger( 'added_to_cart', [ response.fragments, response.cart_hash, $thisbutton ] );
// Remove existing notices
$( '.woocommerce-error, .woocommerce-message, .woocommerce-info' ).remove();
// Add new notices
form.closest('.product').before(response.fragments.notices_html)
form.unblock();
}
});
});
});
PHP:
/* WOOCOMMERCE AJAX ADD TO CART
--------------------------------------------------- */
function ace_ajax_add_to_cart_handler() {
WC_Form_Handler::add_to_cart_action();
WC_AJAX::get_refreshed_fragments();
}
/* Add fragments for notices. */
function ace_ajax_add_to_cart_add_fragments( $fragments ) {
$all_notices = WC()->session->get( 'wc_notices', array() );
$notice_types = apply_filters( 'woocommerce_notice_types', array( 'error', 'success', 'notice' ) );
ob_start();
foreach ( $notice_types as $notice_type ) {
if ( wc_notice_count( $notice_type ) > 0 ) {
wc_get_template( "notices/{$notice_type}.php", array(
'messages' => array_filter( $all_notices[ $notice_type ] ),
'notices' => array_filter( $all_notices[ $notice_type ] ),
) );
}
}
$fragments['notices_html'] = ob_get_clean();
wc_clear_notices();
return $fragments;
}
add_action( 'wc_ajax_ace_add_to_cart', 'ace_ajax_add_to_cart_handler' );
add_action( 'wc_ajax_nopriv_ace_add_to_cart', 'ace_ajax_add_to_cart_handler' );
remove_action( 'wp_loaded', array( 'WC_Form_Handler', 'add_to_cart_action' ), 20 ); // Remove WC Core add to cart handler to prevent double-add
add_filter( 'woocommerce_add_to_cart_fragments', 'ace_ajax_add_to_cart_add_fragments' );
To enable Ajax add to cart for simple and variable products on Single product pages you need something different, building a custom Ajax add to cart function that handles also custom product fields and cart item data manipulation (what WooCommerce default Ajax add to cart doesn't allow).
Try the following fully tested on WooCommerce version 4.9.0:
add_action( 'wp_footer', 'single_product_ajax_add_to_cart_js_script' );
function single_product_ajax_add_to_cart_js_script() {
?>
<script>
(function($) {
$('form.cart').on('submit', function(e) {
e.preventDefault();
var form = $(this),
mainId = form.find('.single_add_to_cart_button').val(),
fData = form.serializeArray();
form.block({ message: null, overlayCSS: { background: '#fff', opacity: 0.6 } });
if ( mainId === '' ) {
mainId = form.find('input[name="product_id"]').val();
}
if ( typeof wc_add_to_cart_params === 'undefined' )
return false;
$.ajax({
type: 'POST',
url: wc_add_to_cart_params.wc_ajax_url.toString().replace( '%%endpoint%%', 'custom_add_to_cart' ),
data : {
'product_id': mainId,
'form_data' : fData
},
success: function (response) {
$(document.body).trigger("wc_fragment_refresh");
$('.woocommerce-error,.woocommerce-message').remove();
$('input[name="quantity"]').val(1);
$('.content-area').before(response);
form.unblock();
// console.log(response);
},
error: function (error) {
form.unblock();
// console.log(error);
}
});
});
})(jQuery);
</script>
<?php
}
add_action( 'wc_ajax_custom_add_to_cart', 'custom_add_to_cart_handler' );
add_action( 'wc_ajax_nopriv_custom_add_to_cart', 'custom_add_to_cart_handler' );
function custom_add_to_cart_handler() {
if( isset($_POST['product_id']) && isset($_POST['form_data']) ) {
$product_id = $_POST['product_id'];
$variation = $cart_item_data = $custom_data = array(); // Initializing
$variation_id = 0; // Initializing
foreach( $_POST['form_data'] as $values ) {
if ( strpos( $values['name'], 'attributes_' ) !== false ) {
$variation[$values['name']] = $values['value'];
} elseif ( $values['name'] === 'quantity' ) {
$quantity = $values['value'];
} elseif ( $values['name'] === 'variation_id' ) {
$variation_id = $values['value'];
} elseif ( $values['name'] !== 'add_to_cart' ) {
$custom_data[$values['name']] = esc_attr($values['value']);
}
}
$product = wc_get_product( $variation_id ? $variation_id : $product_id );
// Allow product custom fields to be added as custom cart item data from $custom_data additional array variable
$cart_item_data = (array) apply_filters( 'woocommerce_add_cart_item_data', $cart_item_data, $product_id, $variation_id, $quantity, $custom_data );
// Add to cart
$cart_item_key = WC()->cart->add_to_cart( $product_id, $quantity, $variation_id, $variation, $cart_item_data );
if ( $cart_item_key ) {
// Add to cart successful notice
wc_add_notice( sprintf(
'%s %d × "%s" %s' ,
wc_get_cart_url(),
__("View cart", "woocommerce"),
$quantity,
$product->get_name(),
__("has been added to your cart", "woocommerce")
) );
}
wc_print_notices(); // Return printed notices to jQuery response.
wp_die();
}
}
Code goes in functions.php file of the active child theme (or active theme). Tested and works.
All notices are enable and displayed on the fly:
Handling product custom fields and cart item data manipulation:
This custom Ajax add to cart code handle product custom fields, allowing to add them as custom cart item data.
For that we use woocommerce_add_cart_item_data WooCommerce dedicated hook enabled in our custom Ajax add to cart code, allowing to add product custom fields as custom cart item data or manipulate cart data on the fly.
If we add a product custom input text field with this code:
add_action( 'woocommerce_before_add_to_cart_button', 'product_additional_custom_fields' );
function product_additional_custom_fields() {
echo '<table class="variations" cellspacing="0" width="100px">
<tbody><tr>
<td class="label" style="width:100px"><label for="engraving">' . __("Engraving text") . '</label></td>
<td class="value">
<input type="text" name="engraving" id="engraving" value="" />
</td>
</tr></tbody>
</table>
</br>';
}
Then if you want to pass the field value as custom cart item data, you will use
add_filter( 'woocommerce_add_cart_item_data', 'add_cart_item_custom_data', 10, 5 );
function add_cart_item_custom_data( $cart_item_data, $product_id, $variation_id = 0, $quantity, $custom_data = array() ) {
if ( isset($custom_data['engraving']) && ! empty($custom_data['engraving']) ) {
$cart_item_data['engraving'] = sanitize_text_field($custom_data['engraving']);
}
return $cart_item_data;
}
And you can check with the following, that will display in cart and checkout that custom cart item data:
add_filter( 'woocommerce_get_item_data', 'display_on_cart_and_checkout', 10, 2 );
function display_on_cart_and_checkout( $cart_data, $cart_item ) {
if ( isset($cart_item['engraving']) ) {
$cart_data[] = array(
"name" => __("Engraving text", "woocommerce"),
"value" => $cart_item['engraving']
);
}
return $cart_data;
}
Code goes in functions.php file of the active child theme (or active theme). Tested and works.
Notes:
This code works on the fly as it is, but it's recommended to enqueue the jQuery code as an external file.
On some themes you should replace: $('.content-area').before(response); with $('.products').before(response);
to display the notices correctly…
Thanks for the helpful snippet, but the above code was not working for guest uses, but only for logins. The wc_fragment_refresh does not trigger when you log out And use it as a guest user.
$(document.body).trigger("wc_fragment_refresh");
Regards

Checkbox enabling a percentage discount in WooCommerce Checkout for specific category

The amended code below is based on Add a checkout checkbox field that enable a percentage fee in Woocommerce. I have adapted but wishing to only target a specific category so when a student ticks the box at checkout, defining they are a student, it will deduct 15 percent off their total but only for a specific category range - namely 'online seminars'. It is beyond me so would appreciate some help.
// Add a custom checkbox fields after billing fields
add_action( 'woocommerce_after_checkout_billing_form', 'add_custom_checkout_checkbox', 20 );
function add_custom_checkout_checkbox(){
// Add a custom checkbox field
woocommerce_form_field( 'student_discount_fee', array(
'type' => 'checkbox',
'label' => __(' Yes, I am a student lawyer studying law'),
'class' => array( 'form-row-wide' ),
), '' );
}
// Remove "(optional)" label on "Student discount checkbox" field
add_filter( 'woocommerce_form_field' , 'remove_order_comments_optional_fields_label', 10, 4 );
function remove_order_comments_optional_fields_label( $field, $key, $args, $value ) {
// Only on checkout page for Order notes field
if( 'student_discount_fee' === $key && is_checkout() ) {
$optional = ' <span class="optional">(' . esc_html__( 'optional', 'woocommerce' ) . ')</span>';
$field = str_replace( $optional, '', $field );
}
return $field;
}
// jQuery - Ajax script
add_action( 'wp_footer', 'checkout_fee_script' );
function checkout_fee_script() {
// Only on Checkout
if( is_checkout() && ! is_wc_endpoint_url() ) :
if( WC()->session->__isset('enable_fee') )
WC()->session->__unset('enable_fee')
?>
<script type="text/javascript">
jQuery( function($){
if (typeof wc_checkout_params === 'undefined')
return false;
$('form.checkout').on('change', 'input[name=student_discount_fee]', function(e){
var fee = $(this).prop('checked') === true ? '1' : '';
$.ajax({
type: 'POST',
url: wc_checkout_params.ajax_url,
data: {
'action': 'enable_fee',
'enable_fee': fee,
},
success: function (result) {
$('body').trigger('update_checkout');
},
});
});
});
</script>
<?php
endif;
}
// Get Ajax request and saving to WC session
add_action( 'wp_ajax_enable_fee', 'get_enable_fee' );
add_action( 'wp_ajax_nopriv_enable_fee', 'get_enable_fee' );
function get_enable_fee() {
if ( isset($_POST['enable_fee']) ) {
WC()->session->set('enable_fee', ($_POST['enable_fee'] ? true : false) );
}
die();
}
// Add a custom dynamic 15% fee
add_action( 'woocommerce_cart_calculate_fees', 'custom_percentage_fee', 20, 1 );
function custom_percentage_fee( $cart ) {
// Only on checkout
if ( ( is_admin() && ! defined( 'DOING_AJAX' ) ) || ! is_checkout() )
return;
$percent = -33.33333333333333;
if( WC()->session->get('enable_fee') )
$cart->add_fee( __( 'STUDENT LAWYER DISCOUNT', 'woocommerce')." ", ($cart->get_subtotal() * $percent / 100) );
}
// hide coupon field on cart page
function hide_coupon_field_on_cart( $enabled ) {
if ( is_cart() ) {
$enabled = false;
}
return $enabled;
}
add_filter( 'woocommerce_coupons_enabled', 'hide_coupon_field_on_cart' );
// hide coupon field on checkout page
function hide_coupon_field_on_checkout( $enabled ) {
if ( is_checkout() ) {
$enabled = false;
}
return $enabled;
}
add_filter( 'woocommerce_coupons_enabled', 'hide_coupon_field_on_checkout' );
Update 3
Use the following revisited code with an additional custom conditional function that check if items are only from specific product categories and can also give the non discounted subtotal for the items from your specific product category(ies).
You will have to set in that function your correct product category(ies) in the array and you can use term name(s), slug(s) or Id(s).
The subtotal is now calculated only for items from your specific product category for the discount and it's a non discounted subtotal, so you don't need to hide anymore the coupon field.
The checkbox is displayed when there is at least an item from your specific product category.
// Custom conditional function that check for specific product categories (and calculate their subtotal)
function check_cart_items_for_specific_categories( $type = 'boolean') {
$categories = array('online-seminars'); // <=== Here define your product category (name, slug or Id)
$category_found = false; // Initializing
$item_subtotal = 0; // Initializing
foreach( WC()->cart->get_cart() as $item ) {
if ( has_term( $categories, 'product_cat', $item['product_id'] ) ) {
$category_found = true;
$item_subtotal += $item['line_total'];
}
}
if ( $type === 'subtotal' ) {
return $item_subtotal;
} else {
return $category_found;
}
}
// Add a custom checkbox fields after billing fields
add_action( 'woocommerce_after_checkout_billing_form', 'add_custom_checkout_checkbox', 20 );
function add_custom_checkout_checkbox(){
if( ! check_cart_items_for_specific_categories() ) return; // Exit
// Add a custom checkbox field
woocommerce_form_field( 'student_discount_fee', array(
'type' => 'checkbox',
'label' => __(' Yes, I am a student lawyer studying law'),
'class' => array( 'form-row-wide' ),
), '' );
}
// Remove "(optional)" label on "Student discount checkbox" field
add_filter( 'woocommerce_form_field' , 'remove_order_comments_optional_fields_label', 10, 4 );
function remove_order_comments_optional_fields_label( $field, $key, $args, $value ) {
// Only on checkout page for Order notes field
if( 'student_discount_fee' === $key && is_checkout() && check_cart_items_for_specific_categories() ) {
$optional = ' <span class="optional">(' . esc_html__( 'optional', 'woocommerce' ) . ')</span>';
$field = str_replace( $optional, '', $field );
}
return $field;
}
// jQuery - Ajax script
add_action( 'wp_footer', 'checkout_fee_script' );
function checkout_fee_script() {
// Only on Checkout
if( is_checkout() && ! is_wc_endpoint_url() && check_cart_items_for_specific_categories() ) :
if( WC()->session->__isset('enable_fee') )
WC()->session->__unset('enable_fee')
?>
<script type="text/javascript">
jQuery( function($){
if (typeof wc_checkout_params === 'undefined')
return false;
$('form.checkout').on('change', 'input[name=student_discount_fee]', function() {
var fee = $(this).prop('checked') === true ? '1' : '';
$.ajax({
type: 'POST',
url: wc_checkout_params.ajax_url,
data: {
'action' : 'enable_fee',
'enable_fee': fee,
},
success: function (result) {
$('body').trigger('update_checkout');
},
});
});
});
</script>
<?php
endif;
}
// Get Ajax request and saving to WC session
add_action( 'wp_ajax_enable_fee', 'get_enable_fee' );
add_action( 'wp_ajax_nopriv_enable_fee', 'get_enable_fee' );
function get_enable_fee() {
if ( isset($_POST['enable_fee']) ) {
WC()->session->set('enable_fee', ($_POST['enable_fee'] ? true : false) );
}
die();
}
// Add a custom dynamic 15% fee
add_action( 'woocommerce_cart_calculate_fees', 'custom_percentage_fee', 20, 1 );
function custom_percentage_fee( $cart ) {
// Only on checkout
if ( ( is_admin() && ! defined( 'DOING_AJAX' ) ) || ! is_checkout() )
return;
if( WC()->session->get('enable_fee') && check_cart_items_for_specific_categories() ) {
$percentage = -33.33333333333333; // Set the percentage discount (negative float number)
$subtotal = check_cart_items_for_specific_categories('subtotal'); // Related items subtotal
$discount = $subtotal * $percentage / 100;
$cart->add_fee( strtoupper( __( 'Student lawyer discount', 'woocommerce') ), $discount );
}
}
Code goes in functions.php file of the active child theme (or active theme). Tested and works.

WooCommerce extra fee on shipping cost if checkbox ship to other address is enabled

Is there an option that, say if a customer wants to ship to another address other than his billing address, can there be an extra fee based on that checkbox? I want that if a customer unchecks that checkbox, a extra fee of € 12.50 is added on the shipping cost. If anyone knows, please let me know :)
The checkbox is the default woocommerce checkbox btw.
I already fixed it by adding below code to the functions.php within your own theme:
add_filter( 'woocommerce_form_field' , 'remove_order_comments_optional_fields_label', 10, 4 );
function remove_order_comments_optional_fields_label( $field, $key, $args, $value ) {
// Only on checkout page for Order notes field
if( 'ship_to_different_address' === $key && is_checkout() ) {
$optional = ' <span class="optional">(' . esc_html__( 'optional', 'woocommerce' ) . ')</span>';
$field = str_replace( $optional, '', $field );
}
return $field;
}
// Ajax / jQuery script
add_action( 'wp_footer', 'ship_to_different_address_script' );
function ship_to_different_address_script() {
// On checkoutpage
if( ( is_checkout() && ! is_wc_endpoint_url() ) ) :
?>
<script type="text/javascript">
jQuery( function($){
if (typeof woocommerce_params === 'undefined')
return false;
console.log('defined');
$('input[name=ship_to_different_address]').click( function(){
var fee = $(this).prop('checked') === true ? '1' : '';
$.ajax({
type: 'POST',
url: woocommerce_params.ajax_url,
data: {
'action': 'ship_to_different_address',
'ship_to_different_address': fee,
},
success: function (result) {
$('body').trigger('update_checkout');
console.log(result);
},
});
});
});
</script>
<?php
endif;
}
// Get the ajax request and set value to WC session
add_action( 'wp_ajax_ship_to_different_address', 'get_ajax_ship_to_different_address' );
add_action( 'wp_ajax_nopriv_ship_to_different_address', 'get_ajax_ship_to_different_address' );
function get_ajax_ship_to_different_address() {
if ( isset($_POST['ship_to_different_address']) ) {
WC()->session->set('ship_to_different_address', ($_POST['ship_to_different_address'] ? '1' : '0') );
echo WC()->session->get('ship_to_different_address');
}
die();
}
// Add / Remove a custom fee
add_action( 'woocommerce_cart_calculate_fees', 'add_remove_ship_to_different_address', 10, 1 );
function add_remove_ship_to_different_address( $cart )
{
// Only on checkout
if ((is_admin() && !defined('DOING_AJAX')) || is_cart())
return;
$fee_amount = 12.50;
if (WC()->session->get('ship_to_different_address'))
$cart->add_fee(__('Shipping fee', 'woocommerce'), $fee_amount);
}

Remove shipping cost if custom checkbox is checked in WooCommerce Checkout

I am trying to set the price of shipping rates to $0.00 if a checkbox in the checkout fields is checked.
Current Attempt:
function no_shipping_for_own_ups($rates,$package) {
foreach ($rates as $rate) {
//Set the price
$rate->cost = 0;
}
return $rates;
}
function woo_add_cart_ups_y_n_fee( $cart ){
if ( ! $_POST || ( is_admin() && ! is_ajax() ) ) {
return;
}
if ( isset( $_POST['post_data'] ) ) {
parse_str( $_POST['post_data'], $post_data );
} else {
$post_data = $_POST;
}
if (isset($post_data['billing_ups_yn'])) {
add_filter( 'woocommerce_package_rates','no_shipping_for_own_ups', 99, 2 );
}
}
add_action( 'woocommerce_cart_calculate_fees', 'woo_add_cart_ups_y_n_fee', 43, 1 );
As $post_data['billing_ups_yn'] being the checkbox that I set to update the checkout when triggered.
Simply if the checkbox is checked, then apply the filter to set shipping rates to 0.
This, however, isn't working.
To alter shipping methods cost via Ajax on a custom javascript event in checkout page is quiet more complicated than conditionally altering fees or anything else as you will see below.
To store the Ajax data I use WC_Sessions and to alter Shipping methods costs will only work if you manipulate the shipping sessions data
The full working code:
// Add a Custom checkbox field for shipping options (just for testing)
add_action( 'woocommerce_after_checkout_billing_form', 'custom_billing_checkbox_for_testing', 10, 1 );
function custom_billing_checkbox_for_testing( $checkout ) {
$field_id = 'billing_ups_yn';
// Get the checked state if exist
$billing_ups = WC()->session->get('billing_ups' );
if(empty($billing_ups))
$billing_ups = $checkout->get_value( $field_id );
// Add the custom checkout field (checkbox)
woocommerce_form_field( $field_id, array(
'type' => 'checkbox',
'class' => array( 'form-row-wide' ),
'label' => __('Billing UPS'),
), $billing_ups );
}
// function that gets the Ajax data
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' );
function woo_get_ajax_data() {
if ( $_POST['billing_ups'] == '1' ){
WC()->session->set('billing_ups', '1' );
} else {
WC()->session->set('billing_ups', '0' );
}
echo json_encode( WC()->session->get('billing_ups' ) );
die(); // Alway at the end (to avoid server error 500)
}
// Conditionally changing the shipping methods costs
add_filter( 'woocommerce_package_rates','conditional_custom_shipping_cost', 90, 2 );
function conditional_custom_shipping_cost( $rates, $package ) {
if ( WC()->session->get('billing_ups' ) == '1' ){
foreach ( $rates as $rate_key => $rate_values ) {
// Not for "Free Shipping method" (all others only)
if ( 'free_shipping' !== $rate_values->method_id ) {
// Set the rate cost
$rates[$rate_key]->cost = 0;
// Set taxes rate cost (if enabled)
$taxes = array();
foreach ($rates[$rate_key]->taxes as $key => $tax)
if( $rates[$rate_key]->taxes[$key] > 0 ) // set the new tax cost
$taxes[$key] = 0;
$rates[$rate_key]->taxes = $taxes;
}
}
}
return $rates;
}
// Enabling, disabling and refreshing session shipping methods data
add_action( 'woocommerce_checkout_update_order_review', 'refresh_shipping_methods', 10, 1 );
function refresh_shipping_methods( $post_data ){
$bool = true;
if ( WC()->session->get('billing_ups' ) == '1' ) $bool = false;
// Mandatory to make it work with shipping methods
foreach ( WC()->cart->get_shipping_packages() as $package_key => $package ){
WC()->session->set( 'shipping_for_package_' . $package_key, $bool );
}
WC()->cart->calculate_shipping();
}
// The Jquery script
add_action( 'wp_footer', 'custom_checkout_script' );
function custom_checkout_script() {
?>
<script type="text/javascript">
jQuery( function($){
// update cart on delivery location checkbox option
$('#billing_ups_yn_field input').change( function () {
var checked = 0;
if ( $('#billing_ups_yn').is(':checked') )
checked = 1;
$.ajax({
type: 'POST',
url: wc_checkout_params.ajax_url,
data: {
'action': 'woo_get_ajax_data',
'billing_ups': checked,
},
success: function (result) {
$('body').trigger('update_checkout');
console.log('response: '+result); // just for testing
},
error: function(error){
console.log(error); // just for testing
}
});
});
});
</script>
<?php
}
Code goes in function.php file of your active child theme (or active theme).
Tested and works.
Update related to your comment:
If you wish to have always the checkbox unchecked by default at load you will replace the first function by this one:
// Add a Custom checkbox field for shipping options (just for testing)
add_action( 'woocommerce_after_checkout_billing_form', 'custom_billing_checkbox_for_testing', 10, 1 );
function custom_billing_checkbox_for_testing( $checkout ) {
$field_id = 'billing_ups_yn';
// Add the custom checkout field (checkbox)
woocommerce_form_field( $field_id, array(
'type' => 'checkbox',
'class' => array( 'form-row-wide' ),
'label' => __('Billing UPS'),
), '' );
}
I have similar project about 3 years ago and has radio button and date picker that will both modify and update the shipping details/amount when changed, the radio button will modify Shipping surcharge and the date picker will have -10 discount price when Saturday and Friday is selected from the calendar.
working example here
I assume you had knowledge with PHP and AJax and can modify this, you only need to modify few things like the session value and calculation as well as those jquery selector and form fields selector
function to handle ajax request, the purpose is to only assign $_SESSION value
add_action('wp_ajax_woo_modify_charges', 'etq_calculate', 10);
add_action('wp_ajax_nopriv_woo_modify_charges', 'etq_calculate', 10);
function etq_calculate() {
global $woocommerce;
$charge = isset($_POST['billing_area']) ? $_POST['billing_area'] : 'no';
$deldate = isset($_POST['jck_delivery_date']) ? $_POST['jck_delivery_date'] : '06/08/2015';
$delday = strtotime(str_replace('/', '-', $deldate));
$day = date('l', $delday);
if ( $day === 'Saturday' || $day === 'Friday') $val = -10;
else $val = 0;
if ( $charge === 'no' ) $surchage = 0;
else $surchage = 10;
if( !isset($_SESSION) ) session_start();
$_SESSION['val'] = $val;
$_SESSION['surcharge'] = $surchage;
}
Next function is to hook the modification on woocommerce_cart_calculate_fees from the value of $_SESSION.. this is where the price update happens
add_action('woocommerce_cart_calculate_fees', 'woo_change_cart_fee');
function woo_change_cart_fee() {
if(!isset($_SESSION)) session_start();
$surcharge = isset($_SESSION['surcharge']) ? $_SESSION['surcharge'] : 0;
$discount = isset($_SESSION['val']) ? $_SESSION['val'] : 0;
if ( $surcharge !== '0' ) WC()->cart->add_fee('Shipping Surchage', $surcharge, false, '');
if ( $discount !== '0' ) WC()->cart->add_fee('Delivery Discount', $discount, false, '');
}
then for jquery script that handles ajax
(function($){
'use strict';
$(document).ready( function() {
var $date_field = $('#jck_delivery_date');
// update cart on delivery date changes
$('#jck_delivery_date').bind('change', function () {
if ($('#billing_area_yes').is(':checked')) {
var surcharge = $('#billing_area_yes').val();
$('#billing_area_yes').prop('checked', true);
} else {
var surcharge = 'no';
}
var deldate = $('#jck_delivery_date').val();
var data = {
action: 'woo_modify_charges',
jck_delivery_date: deldate,
billing_area: surcharge
};
$.ajax({
type: 'POST',
url: wc_checkout_params.ajax_url,
data: data,
success: function (code) {
console.log(code);
//jQuery('.woocommerce-error, .woocommerce-message').remove();
if (code === '0') {
//$form.before(code);
$('body').trigger('update_checkout');
}
},
dataType: 'html'
});
return false;
});
// update cart on delivery location checkbox option
$('#billing_area_field input').change( function () {
if ($('#billing_area_yes').is(':checked')) {
var surcharge = $('#billing_area_yes').val();
} else {
var surcharge = 'no';
}
var deldate = $('#jck_delivery_date').val();
console.log( surcharge );
var data = {
action: 'woo_modify_charges',
billing_area: surcharge,
jck_delivery_date: deldate,
};
$.ajax({
type: 'POST',
url: wc_checkout_params.ajax_url,
data: data,
success: function (code) {
console.log(code);
//jQuery('.woocommerce-error, .woocommerce-message').remove();
if (code === '0') {
//$form.before(code);
$('body').trigger('update_checkout');
}
},
dataType: 'html'
});
return false;
});
});
})(jQuery);

Categories