Enable delivery time options for a specific state in Woocommerce checkout

为君一笑 提交于 2020-08-23 09:49:09

问题


Based on "Add a custom checkbox in WooCommerce checkout which value shows in admin edit order", I am trying to display custom radio buttons fields only if customer state is NewYork to let customer pick a delivery time in checkout page by choosing a delivery time option. Then admin could see the chosen delivery time in admin order edit pages.

This image will explain everything:

Here is my code attempt (with one checkbox for testing):

$user_state = get_user_meta( get_current_user_id(), 'billing_state')
if($user_state=='NY'){
add_action( 'woocommerce_review_order_before_submit', 'my_custom_checkout_field' );
function my_custom_checkout_field() {
    echo '<div id="my_custom_checkout_field">';

    woocommerce_form_field( 'my_field_name', array(
        'type'      => 'checkbox',
        'class'     => array('input-checkbox'),
        'label'     => __('My custom checkbox'),
        'required'
    ),  WC()->checkout->get_value( 'my_field_name' ) );
    echo '</div>';
}

// Save the custom checkout field in the order meta, when checkbox has been checked
add_action( 'woocommerce_checkout_update_order_meta', 'custom_checkout_field_update_order_meta', 10, 1 );
function custom_checkout_field_update_order_meta( $order_id ) {
    if ( ! empty( $_POST['my_field_name'] ) )
            update_post_meta( $order_id, 'my_field_name', $_POST['my_field_name'] );
}

// Display the custom field result on the order edit page (backend) when checkbox has been checked
add_action( 'woocommerce_admin_order_data_after_billing_address', 'display_custom_field_on_order_edit_pages', 10, 1 );
function display_custom_field_on_order_edit_pages( $order ){
    $my_field_name = get_post_meta( $order->get_id(), 'my_field_name', true );
    if( $my_field_name == 1 )
        echo '<p><strong>My custom field: </strong> <span style="color:red;">Is enabled</span></p>';
}}

But the custom field value isn't displayed. Any help is appreciated.


回答1:


First you need to include your state condition (New York) inside the function that display your custom radio buttons on checkout page:

if( WC()->customer->get_shipping_state() == 'NY' ) {
    // Do something for customers from "New York"
} 

To make this possible Ajax and WC_Session is required, because checkout page is Ajax refreshed and it will not keep the customer choice.

So I have revisited all your existing code:

// Custom setting function: Here define your delivery options for "New york"
function get_newyork_delivery_options(){
    return array(
        '9am-2pm'   => __('9 AM - 2 PM'),
        '2pm-6pm'   => __('2 PM - 6 PM'),
        '6pm-9pm'   => __('6 PM - 9 PM'),
    );
}

// Display delivery custom radio buttons field in checkout for "New york" state
add_action( 'woocommerce_review_order_after_shipping', 'display_delivery_choice_field', 20 );
function display_delivery_choice_field(){
    // Only for "New York" state
    if( WC()->customer->get_shipping_state() == 'NY' ) :

    $choice  = WC()->session->get('delivery_choice');

    // Display the radio buttons
    echo '<tr class="delivery-options">
    <th>' . __("Delivery time") . '<br><em>(' . __("for New York") . ')</em></th>
    <td><span class="woocommerce-input-wrapper">';

    foreach ( get_newyork_delivery_options() as $key => $label ) {
        $checked  = $choice == $key ? 'checked="checked"' : '';
        $field_id = 'delivery_time' . $key;

        echo '<label for="' . $field_id . '" class="radio " style="display:block">
        <input type="radio" class="input-radio " id="' . $field_id . '" name="delivery_time" value="' . $key . '" ' . $checked . '> ' . $label;
        echo '</label>';
    }
    echo '</span></td>
    <tr>';

    endif;
}

// jQuery - Ajax script
add_action( 'wp_footer', 'checkout_delivery_script' );
function checkout_delivery_script() {
    // Only on Checkout
    if( is_checkout() && ! is_wc_endpoint_url() ) :

    if( WC()->session->__isset('delivery_choice') )
        WC()->session->__unset('delivery_choice')
    ?>
    <script type="text/javascript">
    jQuery( function($){
        if (typeof wc_checkout_params === 'undefined')
            return false;

        $('form.checkout').on('change', 'input[name="delivery_time"]', function(){
            var delivery = $(this).val();

            $.ajax({
                type: 'POST',
                url: wc_checkout_params.ajax_url,
                data: {
                    'action': 'delivery_choice',
                    'delivery_choice': delivery,
                },
                success: function (result) {
                    $('body').trigger('update_checkout');
                },
            });
        });
    });
    </script>
    <?php
    endif;
}

// Get Ajax request and saving to WC session
add_action( 'wp_ajax_delivery_choice', 'get_delivery_choice' );
add_action( 'wp_ajax_nopriv_delivery_choice', 'get_delivery_choice' );
function get_delivery_choice() {
    if ( isset($_POST['delivery_choice']) ) {
        WC()->session->set('delivery_choice', esc_attr( $_POST['delivery_choice'] ) );
        echo WC()->session->get('delivery_choice');
    }
    die();
}

// Save the chosen delivery time as order meta data
add_action('woocommerce_checkout_create_order', 'custom_checkout_field_added_as_order_meta', 10, 2 );
function custom_checkout_field_added_as_order_meta( $order, $data ) {
    if ( isset( $_POST['delivery_option'] ) )
        $order->add_meta_data( '_delivery_time', esc_attr( $_POST['delivery_time'] ) );
}

// Display the chosen delivery time on order totals lines everywhere (except admin)
add_action('woocommerce_get_order_item_totals', 'display_bacs_option_on_order_totals', 10, 3 );
function display_bacs_option_on_order_totals( $total_rows, $order, $tax_display ) {
    if ( $delivery_time = $order->get_meta('_delivery_time') ) {
        $sorted_total_rows = [];

        foreach ( $total_rows as $key_row => $total_row ) {
            $sorted_total_rows[$key_row] = $total_row;
            if( $key_row === 'shipping' ) {
                $sorted_total_rows['delivery_time'] = [
                    'label' => __( "Delivery time", "woocommerce"),
                    'value' => esc_html( get_newyork_delivery_options()[$delivery_time] ),
                ];
            }
        }
        $total_rows = $sorted_total_rows;
    }
    return $total_rows;
}

// Display the chosen delivery option on admin order edit page for new york state
add_action( 'woocommerce_admin_order_data_after_shipping_address', 'display_custom_field_on_order_edit_pages', 10, 1 );
function display_custom_field_on_order_edit_pages( $order ){
    if( $key = $order->get_meta( '_delivery_time' ) ) {
        $label = get_newyork_delivery_options()[$key];
        echo '<p><strong>Delivery <em>(New York)</em>: </strong> <span style="color:green;">' . $label . '</span></p>';
    }
}

Code goes in function.php file of the active child theme (or active theme). Tested and works.



来源:https://stackoverflow.com/questions/57690187/enable-delivery-time-options-for-a-specific-state-in-woocommerce-checkout

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!