The code provided was mostly un-useful… I have make a lot of changes and optimizations. All my code is commented, it's tested on WooCommerce 3+ and perfectly works.
You will have to add your "incredibly complex code used to calculate delivery costs omitted"…
1) JAVASCRIPT FOR CONDITIONAL CHECKOUT FIELDS LIVE EVENTS
The only way to get the hand on customer live events (browser side) is javascript/jQuery. So this is not easy because WooCommerce use already a lot of javascript/jQuery/Ajax on checkout page…
I have included the javascript code into the hooked function, but you should save it in a separate file and register this script file with classic WordPress registering script function, like in this thread:
Checkout fields: Hiding and showing existing fields
2) USE EXISTING AVAILABLE SHIPPING METHODS (DYNAMIC PRICES CALCULATION):
You don't need to create any shipping rate. You can use:
-
local_pickup available method for your "TAKE WAY"
-
flat_rate available method for your "Delivery" (with dynamic price calculations)
For each of your shipping zones, enable, set and rename (label name) the 2 methods in Woocommerce > Settings > Shipping:
For the flat rate you can set any minimal amount (that will be overwritten by your calculations)…
If you make changes you need to refresh shipping cached data: disable, save and enable, save those methods for the current shipping zone.
3) SAVING THE SHIPPING TIME TO ORDER META DATA:
I have add some code for that and it's save in 2 custom meta fields:
- One for the chosen shipping
- The other for the time
4) DISPLAYING THE CHOSEN SHIPPING TYPE AND TIME IN A METABOX (IN ORDER EDIT PAGES):
I have also add some code for that.
FINALY HERE IS THE CODE:
add_action( 'woocommerce_after_order_notes', 'my_custom_checkout_field' );
function my_custom_checkout_field( $checkout ) {
// The 2 Options arrays in imput select
$delivery_time_list[''] = $takeaway_time_list[''] = __('Select an hour');
for($h = 10, $i = 0; $i < 8; $i++ ){
if( $i % 2 == 0 ){
$time = $h.':00';
$delivery_time_list[$time] = 'deliver '.$time;
} else {
$time = $h.':30';
$h++;
}
$takeaway_time_list[$time] = 'takeaway '.$time;
}
echo '<div id="delivery_checkout_fields"><h3>' . __('Shipping time options') . '</h3>';
woocommerce_form_field( 'delivery_time', array(
'type' => 'select',
'class' => array('delivery-time form-row-wide'),
'label' => __('Delivery time'),
'options' => $delivery_time_list,
), $checkout->get_value( 'delivery_time' ) );
woocommerce_form_field( 'takeaway_time', array(
'type' => 'select',
'class' => array('takeaway-time form-row-wide'),
'label' => __('Take away time'),
'options' => $takeaway_time_list,
), $checkout->get_value( 'takeaway_time' ) );
echo '</div>';
$required = esc_attr__( 'required', 'woocommerce' );
?>
<script>
jQuery(function($){
var choosenShipMethod = $('input[name^="shipping_method"]:checked').val().split(':')[0], // Choosen shipping method slug
required = '<abbr class="required" title="<?php echo $required; ?>">*</abbr>'; // Required html
// TESTING: displaying in console the choosen shipping
console.log('Chosen shipping: '+choosenShipMethod);
// Function that shows or hide imput select fields
function showHide( actionToDo='show', selector='' ){
if( actionToDo == 'show' )
$(selector).show(function(){
$(this).addClass("validate-required");
$(this).removeClass("woocommerce-validated");
$(this).removeClass("woocommerce-invalid woocommerce-invalid-required-field");
$(selector+' label').append(required);
//console.log('Selector (show): '+selector);
});
else
$(selector).hide(function(){
$(this).removeClass("validate-required");
$(this).removeClass("woocommerce-validated");
$(this).removeClass("woocommerce-invalid woocommerce-invalid-required-field");
$(selector+' label > .required').remove();
//console.log('Selector (hide): '+selector);
});
}
// Initialising at start (Based on the choosen shipping method)
if( choosenShipMethod == 'flat_rate' ) // Choosen "Delivery" (Hidding "Take away")
{
showHide('show','#delivery_time_field' );
showHide('hide','#takeaway_time_field' );
}
else if( choosenShipMethod == 'local_pickup' ) // Choosen "Take away" (Hidding "Delivery")
{
showHide('show','#takeaway_time_field' );
showHide('hide','#delivery_time_field' );
}
else // No shipping choosen yet (Hidding BOTH shipping dropdown hour selectors
{
showHide('hide','#delivery_time_field' );
showHide('hide','#takeaway_time_field' );
$('#delivery_checkout_fields').hide();
}
// When shipping method is changed (Live event)
$( 'form.checkout' ).on( 'change', 'input[name^="shipping_method"]', function() {
var changedShipMethod = $('input[name^="shipping_method"]:checked').val().split(':')[0];
if( changedShipMethod == 'flat_rate' )
{
// Choose "Delivery" | Show "Delivery" and Hide "Take away"
$('#delivery_checkout_fields').show();
showHide('show','#delivery_time_field' );
showHide('hide','#takeaway_time_field' );
}
else if( changedShipMethod == 'local_pickup' )
{
// Choose "Take away" | Show "Take away" and Hide "Delivery"
$('#delivery_checkout_fields').show();
showHide('show','#takeaway_time_field' );
showHide('hide','#delivery_time_field' );
}
console.log("Chosen shipping: "+changedShipMethod);
});
// When an hour is selected (LIVE event)
$('#delivery_checkout_fields select').change( function(){
if( $(this).val() != '')
$(this).parent().removeClass("validate-required");
else
$(this).parent().addClass("validate-required");
console.log("Selector value: "+$(this).val());
});
// "select.shipping_method, input[name^="shipping_method"], #ship-to-different-address input, .update_totals_on_change select, .update_totals_on_change input[type="radio"], .update_totals_on_change input[type="checkbox"]"
//"function (){t.reset_update_checkout_timer(),t.dirtyInput=!1,e(document.body).trigger("update_checkout")}"
});
</script>
<?php
}
// Process the checkout (Checking if required fields are not empty)
add_action('woocommerce_checkout_process', 'ba_custom_checkout_field_process');
function ba_custom_checkout_field_process() {
$delivery_time = $takeaway_time = 0;
if ( $_POST['delivery_time'] ) $delivery_time = 1;
if ( $_POST['takeaway_time'] ) $takeaway_time = 1;
// Only one message is possible for both
if ( ( $delivery_time + $takeaway_time ) == 0 ){
wc_add_notice( __('Please select a <strong>shipping time</strong>.' ), 'error');
}
}
## CALCULATING THE DELIVERY FEE (BASED ON COUNTING THE DIFFERENT DATES For all items) ##
add_filter( 'woocommerce_package_rates', 'custom_shipping_flat_rate_cost_calculation', 10, 2 );
function custom_shipping_flat_rate_cost_calculation( $rates, $package )
{
## --- CALCULATIONS Based on CART DATA (if needed) --- ##
foreach(WC()->cart->get_cart() as $cart_item ):
// HERE your incredibly complex code used to calculate delivery costs
endforeach;
## --- CHANGING DYNAMICALLY THE METHODS COSTS --- ##
foreach($rates as $rate_key => $rate_values):
$method_id = $rate_values->method_id;
$rate_id = $rate_values->id;
// "DELIVERY" - "local_pickup" method (if needed)
if ( 'flat_rate' === $method_id ){
// HERE your incredibly complex code used to calculate delivery costs
// Change the price cost
$price_excl_tax = $rates[$rate_id]->cost + 2.5;
$rates[$rate_id]->cost = number_format($price_excl_tax, 2);
$tax_calculation = $rates[$rate_id]->taxes[0] * 0.1;
$rates[$rate_id]->taxes[0] = number_format($tax_calculation, 2);
}
// "TAKE WAY" - "local_pickup" method (if needed)
elseif ( 'local_pickup' === $method_id )
{
// do something if needed
}
endforeach;
return $rates;
}
// Save the "shipping time" in order meta data
add_action( 'woocommerce_checkout_update_order_meta', 'save_shipping_time_in_order_meta', 100, 1 );
function save_shipping_time_in_order_meta( $order_id ) {
// Take away time
$takeaway_time = $_POST['takeaway_time'];
if ( ! empty( $takeaway_time ) ){
add_post_meta( $order_id, '_shipping_time', $takeaway_time );
add_post_meta( $order_id, '_shipping_type', __('Take away', 'woocommerce' ) );
}
// Delivery time
$delivery_time = $_POST['delivery_time'];
if ( ! empty( $delivery_time ) ){
add_post_meta( $order_id, '_shipping_time', $delivery_time );
add_post_meta( $order_id, '_shipping_type', __('Delivery', 'woocommerce' ) );
}
}
// Adding shipping time metabox (on right side) to Order edit pages
add_action( 'add_meta_boxes', 'add_order_shipping_time_meta_boxe' );
function add_order_shipping_time_meta_boxe(){
add_meta_box(
'woocommerce-order-shipping-time-values', __( 'Shipping type and time', 'woocommerce' ),
'order_shipping_time_values', 'shop_order', 'side', 'default'
);
}
// Adding content to shipping time metabox to Order edit pages
function order_shipping_time_values(){
global $post;
$type = get_post_meta($post->ID, '_shipping_type', true);
$time = get_post_meta($post->ID, '_shipping_time', true);
echo "<p><strong>Type:</strong> $type | <strong>time:</strong> $time</p>";
}
Code goes in function.php file of your active child theme (or theme) or also in any plugin file.
This code is tested on WooCommerce 3+ and works.