WooCommerce:在检验验证失败后更新自定义字段

时间:2022-10-25 10:01:23

In my project I'm customizing some of the WooCommerce features.
My "shipping methods" are:
1. delivery
2. take away

在我的项目中,我定制了一些WooCommerce特性。我的“运输方法”是:1。交货2。带走

I also added a custom field in the checkout page that is a <select> populated with the valid times for delivery (case "1") or for the take away (case "2").

我还在checkout页面中添加了一个自定义字段,该字段是

It may happen that a user selects 2. take away in the cart page, then selects a time valid for "2", but then changes to 1. delivery and the selected time may not be valid anymore, neither the option list and the custom field label.

用户可能会选择2。在cart页面中取出,然后选择一个对“2”有效的时间,然后更改为1。交付和选择的时间可能不再有效,选项列表和自定义字段标签也不再有效。

Of course i'm using the woocommerce_checkout_process hook to warn the user via wc_add_notice(), but even if the woocommerce_checkout_fields hook is triggered (that's where i create the select list), the <select> values are not updated.

当然,我正在使用woocommerce_checkout_process钩子通过wc_add_notice()向用户发出警告,但是即使触发了woocommerce_checkout_fields钩子(这就是我创建select列表的地方),

I think there is an AJAX call that is related only to the shipping method and doesn't update the other checkout fields, although woocommerce_checkout_fields hook is triggered.

我认为有一个AJAX调用只与传递方法相关,不会更新其他的签出字段,尽管会触发woocommerce_checkout_fields hook。

How to update the custom fields? Do i need some js/jquery/AJAX?

如何更新自定义字段?我需要一些js/jquery/AJAX吗?

Or: can a custom field be related to a shipping method (and get updated via AJAX with it)? How?

或者:自定义字段可以与传送方法相关(并通过使用它的AJAX进行更新)吗?如何?

EDIT

编辑

Custom field code:

自定义字段代码:

add_filter( 'woocommerce_checkout_fields', 'fty_filter_checkout_fields' );
function my_filter_checkout_fields($fields) {
    $must_deliver   =   WC()->cart->shipping_total > 0.0;   // true=deliver, false=take away

    // some complex code to calculate time lists omitted, samples array instead:

    $delivery_time_list =   array(
        "deliver 10:00",
        "deliver 11:00",
        "deliver 12:00",
        "deliver 13:00"
    );

    $takeaway_time_list =   array(
        "takeaway 10:00",
        "takeaway 10:30",
        "takeaway 11:00",
        "takeaway 11:30",
        "takeaway 12:00",
        "takeaway 12:30",
        "takeaway 13:00",
        "takeaway 13:30"
    );

    // add the new conditional field
    if($must_deliver) {
        $fields['my_delivery_datetime'] = array(
            'my_delivery_time' => array(
                'type'      => 'select',
                'options'   => $delivery_time_list,
                'required'  => true,
                'label'     => __('Delivery time')
            )
        );
    } else {
        $fields['my_delivery_time'] = array(
            'my_delivery_time' => array(
                'type'      => 'select',
                'options'   => $takeaway_time_list,
                'required'  => true,
                'label'     => __('Take away time')
            )
        );
    }

    return $fields;
}

an idea of the validation code:

验证码的概念:

add_action('woocommerce_checkout_process', 'my_checkout_date_time_validation', 30, 1);
function my_checkout_date_time_validation($doh) {
    $time = filter_input(INPUT_POST, 'my_delivery_time');
    $shipping = filter_input(INPUT_POST, 'shipping_method', FILTER_DEFAULT, FILTER_REQUIRE_ARRAY);

    if(strpos($time, "deliver")!==FALSE && strpos($shipping[0], "local_pickup")!==FALSE) {
        wc_add_notice('Please re-select take away time', 'error');
    } else if(strpos($time, "takeaway")!==FALSE && strpos($shipping[0], "distance_based_rate")!==FALSE) {
        wc_add_notice('Please re-select delivery time', 'error');
    }

}

here's about shipping methods;

这是关于运输方法;

add_action( 'woocommerce_flat_rate_shipping_add_rate', 'add_distance_based_delivery_rate', 10, 2 );
function add_distance_based_delivery_rate( $method, $rate ) {
    $new_rate          = $rate;
    $new_rate['id']    .= ':' . 'distance_based_rate';
    $new_rate['label'] = 'delivery'; // Rename to 'Rushed Shipping'.

    // incredibly complex code used to calculate delivery costs omitted
    $dist_cost  =   1000;

    $new_rate['cost']  += $dist_cost;
    $method->add_rate( $new_rate );
}

Thanx!

谢谢!

1 个解决方案

#1


3  

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.

所提供的代码大部分是无用的……我做了很多修改和优化。我所有的代码都被注释了,它在WooCommerce 3+上进行了测试,并且运行良好。

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…

1)有条件检验字段的JAVASCRIPT LIVE EVENTS(浏览器端)获得客户LIVE EVENTS的唯一途径是JAVASCRIPT /jQuery。这并不容易,因为WooCommerce已经在checkout页面上使用了大量的javascript/jQuery/Ajax……

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:

我已经将javascript代码包含在这个钩形函数中,但是您应该将它保存在一个单独的文件中,并将这个脚本文件注册到经典的WordPress注册脚本函数中,就像在这个线程中:

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:

2)使用现有的运输方法(动态价格计算):不需要创建任何运费。您可以使用:

  • local_pickup available method for your "TAKE WAY"
  • local_pick可用于“TAKE WAY”的方法
  • flat_rate available method for your "Delivery" (with dynamic price calculations)
  • “交付”的flat_rate可用方法(使用动态价格计算)

For each of your shipping zones, enable, set and rename (label name) the 2 methods in Woocommerce > Settings > Shipping:

对于您的每个发货区域,启用、设置和重命名(标签名)Woocommerce >设置> shipping中的两个方法:

WooCommerce:在检验验证失败后更新自定义字段

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:

3)节省了订购元数据的运输时间:我为此添加了一些代码,它保存在两个自定义元数据字段中:

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

4)在METABOX(按顺序编辑页面)中显示所选择的发送类型和时间:我还为此添加了一些代码。

WooCommerce:在检验验证失败后更新自定义字段


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.

代码功能。活动子主题(或主题)或任何插件文件中的php文件。

This code is tested on WooCommerce 3+ and works.

该代码在WooCommerce 3+上进行了测试,并且能够正常工作。

#1


3  

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.

所提供的代码大部分是无用的……我做了很多修改和优化。我所有的代码都被注释了,它在WooCommerce 3+上进行了测试,并且运行良好。

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…

1)有条件检验字段的JAVASCRIPT LIVE EVENTS(浏览器端)获得客户LIVE EVENTS的唯一途径是JAVASCRIPT /jQuery。这并不容易,因为WooCommerce已经在checkout页面上使用了大量的javascript/jQuery/Ajax……

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:

我已经将javascript代码包含在这个钩形函数中,但是您应该将它保存在一个单独的文件中,并将这个脚本文件注册到经典的WordPress注册脚本函数中,就像在这个线程中:

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:

2)使用现有的运输方法(动态价格计算):不需要创建任何运费。您可以使用:

  • local_pickup available method for your "TAKE WAY"
  • local_pick可用于“TAKE WAY”的方法
  • flat_rate available method for your "Delivery" (with dynamic price calculations)
  • “交付”的flat_rate可用方法(使用动态价格计算)

For each of your shipping zones, enable, set and rename (label name) the 2 methods in Woocommerce > Settings > Shipping:

对于您的每个发货区域,启用、设置和重命名(标签名)Woocommerce >设置> shipping中的两个方法:

WooCommerce:在检验验证失败后更新自定义字段

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:

3)节省了订购元数据的运输时间:我为此添加了一些代码,它保存在两个自定义元数据字段中:

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

4)在METABOX(按顺序编辑页面)中显示所选择的发送类型和时间:我还为此添加了一些代码。

WooCommerce:在检验验证失败后更新自定义字段


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.

代码功能。活动子主题(或主题)或任何插件文件中的php文件。

This code is tested on WooCommerce 3+ and works.

该代码在WooCommerce 3+上进行了测试,并且能够正常工作。