WooCommerce:结帐验证失败后更新自定义字段 [英] WooCommerce: update custom fields after checkout validation failure

查看:96
本文介绍了WooCommerce:结帐验证失败后更新自定义字段的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在我的项目中,我正在自定义某些WooCommerce功能.
我的送货方式"是:
1.交货
2.带走

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

我还在结帐页面上添加了一个自定义字段,该字段是<select>,其中填充了交货(案例"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").

可能会发生以下情况:用户在购物车页面中选择2. take away,然后选择对"2"有效的时间,但随后更改为1. delivery,并且所选时间可能不再有效,选项列表和自定义字段标签.

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.

当然,我正在使用woocommerce_checkout_process挂钩通过wc_add_notice()警告用户,但是即使触发了woocommerce_checkout_fields挂钩(这也是我创建选择列表的地方),也不会使用<select>值已更新.

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.

我认为有一个AJAX调用仅与送货方式有关,尽管触发了woocommerce_checkout_fields挂钩,但它不会更新其他结帐字段.

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.

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

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

或者:自定义字段可以与运输方式相关(并通过AJAX进行更新)吗?怎么样?

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

编辑

自定义字段代码:

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;
}

验证代码的构想:

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 );
}

感谢!

推荐答案

所提供的代码几乎没有用……我进行了很多更改和优化.我所有的代码都经过注释,并且已经在WooCommerce 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.

您将必须添加"用于计算交付成本的极其复杂的代码" ...


1)有条件结帐现场直播活动的JAVASCRIPT
掌握客户现场活动(浏览器端)的唯一方法是javascript/jQuery.因此这并不容易,因为WooCommerce在结帐页面上已经使用了很多javascript/jQuery/Ajax ...


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…

我已将javascript代码包含在hooked函数中,但是您应该将其保存在一个单独的文件中,并使用经典的WordPress注册脚本功能来注册此脚本文件,例如在此线程中

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:

结帐字段:隐藏和显示现有字段

2)使用现有的送货方式(动态价格计算):
您无需创建任何运费.您可以使用:

2) USE EXISTING AVAILABLE SHIPPING METHODS (DYNAMIC PRICES CALCULATION):
You don't need to create any shipping rate. You can use:

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

对于每个送货区域,在Woocommerce>设置>送货中启用,设置并重命名(标签名称) 2种方法:

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)节省订购元数据的运输时间:
我为此添加了一些代码,并将其保存在2个自定义元字段中:

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:

  • 一个用于选择的运输方式
  • 其他时间

4)在[METABOX]中显示所选的运输类型和时间(在订单编辑页面中):
我还为此添加了一些代码.

4) DISPLAYING THE CHOSEN SHIPPING TYPE AND TIME IN A METABOX (IN ORDER EDIT PAGES):
I have also add some code for that.

代码终于在这里

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>";
}

代码会出现在活动的子主题(或主题)的function.php文件中,也可能会出现在任何插件文件中.

Code goes in function.php file of your active child theme (or theme) or also in any plugin file.

此代码已在WooCommerce 3+上进行了测试,并且可以正常工作.

This code is tested on WooCommerce 3+ and works.

这篇关于WooCommerce:结帐验证失败后更新自定义字段的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆