WooCommerce 购物车和结帐中运输方式的额外承运人字段 [英] Extra carrier field for shipping methods in WooCommerce cart and checkout

查看:19
本文介绍了WooCommerce 购物车和结帐中运输方式的额外承运人字段的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

灵感来自

在结帐页面页面 (对于选择的特定运输方式):

关于客户订单 (电子邮件通知和管理订单页面也是):

Inspired from Shipping carrier custom fields validation in Woocommerce checkout page answer code, I use following code which displays a select field with shipping companies (this field is displayed only when I choose a specific shipping method):

add_action( 'woocommerce_after_shipping_rate', 'carrier_custom_fields', 20, 2 );
function carrier_custom_fields( $method, $index ) {
    if( ! is_checkout()) return; // Only on the checkout page

    $customer_carrier_method = 'flat_rate:14';

    if( $method->id != $customer_carrier_method ) return; // Mostrar solo para "flat_rate:14"

    $chosen_method_id = WC()->session->chosen_shipping_methods[ $index ];

    // If the chosen shipping method is 'flat_rate: 14', we will show
    if($chosen_method_id == $customer_carrier_method ):

    echo '<div class="custom-carrier2">';

    woocommerce_form_field( 'carrier_name1', array(
        'type'          => 'select',
        'class'         => array('carrier_name2-class form-row-wide'),
        'label'         => __('<strong>Shipping Company</strong>'),
        'required'      => 'true',
        'options'       => array(
            '1'                     => '', // no data means that the field is not selected
            'Shipping Company 1'    => 'Shipping Company 1',
            'Shipping Company 2'    => 'Shipping Company 2',
            'Shipping Company 3'    => 'Shipping Company 3',
            'Shipping Company 4'    => 'Shipping Company 4'
        )
    ), WC()->checkout->get_value( 'carrier_name1' ) );

    echo '</div>';
    endif;
}

// Validate the custom selection field
add_action('woocommerce_checkout_process', 'carrier_checkout_process');
function carrier_checkout_process() {
    if( isset( $_POST['carrier_name1'] ) && empty( $_POST['carrier_name1'] ) )
        wc_add_notice( ( "<strong>Shipping Company</strong> it is a required field." ), "error" );
}

// Save custom fields to sort metadata
add_action( 'woocommerce_checkout_update_order_meta', 'carrier_update_order_meta', 30, 1 );
function carrier_update_order_meta( $order_id ) {
    if( isset( $_POST['carrier_name1'] ))
        update_post_meta( $order_id, 'carrier_name1', sanitize_text_field( $_POST['carrier_name1'] ) );
}

The problem is that it's only displayed on the checkout page and I would like it to show it in cart page, keeping the selected vale on cart page to checkout page.

I think I have found something that says that this transfer of the selected data between the cart and the payment page is done through Ajax, but I am not skilled with Ajax and I don't know how to make that work.

解决方案

To make that work on cart and checkout pages, you will need some additional code using jQuery, Ajax and WC Session variable:

Final update - To make the code more dynamic, we start with a custom function that will handle all required settings:

// Custom function that handle your settings
function carrier_settings(){
    return array(
        'targeted_methods' => array('flat_rate:14'), // Your targeted shipping method(s) in this array
        'field_id'         => 'carrier_name', // Field Id
        'field_type'       => 'select', // Field type
        'field_label'      => '', // Leave empty value if the first option has a text (see below).
        'label_name'       => __("Carrier company","woocommerce"), // for validation and as meta key for orders
        'field_options'    => array(
             // The option displayed at first ( or keep an empty value '',)
            __("Choose a carrier company", "woocommerce"),
            // The carrier companies below (one by line)
            'Company name 1',
            'Company name 2',
            'Company name 3',
            'Company name 4',
        ),
    );
}

Then we can load that settings on any function where it's needed.

Now the Select field with carrier companies displayed for a specific shipping method on cart and checkout pages:

// Display the custom checkout field
add_action( 'woocommerce_after_shipping_rate', 'carrier_company_custom_select_field', 20, 2 );
function carrier_company_custom_select_field( $method, $index ) {
    extract( carrier_settings() ); // Load settings and convert them in variables

    $chosen  = WC()->session->get('chosen_shipping_methods'); // The chosen methods
    $value   = WC()->session->get($field_id);
    $value   = WC()->session->__isset($field_id) ? $value : WC()->checkout->get_value('_'.$field_id);
    $options = array(); // Initializing

    if( ! empty($chosen) && $method->id === $chosen[$index] && in_array($method->id, $targeted_methods)  ) {
        echo '<div class="custom-carrier">';

        // Loop through field otions to add the correct keys
        foreach( $field_options as $key => $option_value ) {
            $option_key = $key == 0 ? '' : $key;
            $options[$option_key] = $option_value;
        }

        woocommerce_form_field( $field_id, array(
            'type'     => $field_type,
            'label'    => '', // Not required if the first option has a text.
            'class'    => array('form-row-wide ' . $field_id . '-' . $field_type ),
            'required' => true,
            'options'  => $options,
        ), $value );

        echo '</div>';
    }
}

The Ajax part: The jQuery sender + PHP WordPress admin Ajax receiver code for the selected carrier company:

// jQuery code (client side) - Ajax sender 
add_action( 'wp_footer', 'carrier_company_script_js' );
function carrier_company_script_js() {
    // Only cart & checkout pages
    if( is_cart() || ( is_checkout() && ! is_wc_endpoint_url() ) ):

    // Load settings and convert them in variables
    extract( carrier_settings() );

    $js_variable = is_cart() ? 'wc_cart_params' : 'wc_checkout_params';

    // jQuery Ajax code
    ?>
    <script type="text/javascript">
    jQuery( function($){
        if (typeof <?php echo $js_variable; ?> === 'undefined')
            return false;

        $(document.body).on( 'change', 'select#<?php echo $field_id; ?>', function(){
            var value = $(this).val();
            $.ajax({
                type: 'POST',
                url: <?php echo $js_variable; ?>.ajax_url,
                data: {
                    'action': 'carrier_name',
                    'value': value
                },
                success: function (result) {
                    console.log(result); // Only for testing (to be removed)
                }
            });
        });
    });
    </script>
    <?php
    endif;
}

// The Wordpress Ajax PHP receiver
add_action( 'wp_ajax_carrier_name', 'set_carrier_company_name' );
add_action( 'wp_ajax_nopriv_carrier_name', 'set_carrier_company_name' );
function set_carrier_company_name() {
    if ( isset($_POST['value']) ){
        // Load settings and convert them in variables
        extract( carrier_settings() );

        if( empty($_POST['value']) ) {
            $value = 0;
            $label = 'Empty';
        } else {
            $value = $label = esc_attr( $_POST['value'] );
        }

        // Update session variable
        WC()->session->set( $field_id, $value );

        // Send back the data to javascript (json encoded)
        echo $label . ' | ' . $field_options[$value];
        die();
    }
}

Then on checkout page, the field validation and saving the chosen carrier company to the order:

// Conditional function for validation
function has_carrier_field(){
    $settings = carrier_settings();
    return array_intersect(WC()->session->get( 'chosen_shipping_methods' ), $settings['targeted_methods']);
}

// Validate the custom selection field
add_action('woocommerce_checkout_process', 'carrier_company_checkout_validation');
function carrier_company_checkout_validation() {
    // Load settings and convert them in variables
    extract( carrier_settings() );

    if( has_carrier_field() && isset( $_POST[$field_id] ) && empty( $_POST[$field_id] ) )
        wc_add_notice(
            sprintf( __("Please select a %s as it is a required field.","woocommerce"),
            '<strong>' . $label_name . '</strong>'
        ), "error" );
}

// Save custom field as order meta data
add_action( 'woocommerce_checkout_create_order', 'save_carrier_company_as_order_meta', 30, 1 );
function save_carrier_company_as_order_meta( $order ) {
    // Load settings and convert them in variables
    extract( carrier_settings() );

    if( has_carrier_field() && isset( $_POST[$field_id] ) && ! empty( $_POST[$field_id] ) ) {
        $order->update_meta_data( '_'.$field_id, $field_options[esc_attr($_POST[$field_id])] );
        WC()->session->__unset( $field_id ); // remove session variable
    }
}

Display the selected carrier on admin order pages, on customer orders and email notifications:

// Display custom field in admin order pages
add_action( 'woocommerce_admin_order_data_after_shipping_address', 'admin_order_display_carrier_company', 30, 1 );
function admin_order_display_carrier_company( $order ) {
    // Load settings and convert them in variables
    extract( carrier_settings() );

    $carrier = $order->get_meta( '_'.$field_id ); // Get carrier company

    if( ! empty($carrier) ) {
        // Display
        echo '<p><strong>' . $label_name . '</strong>: ' . $carrier . '</p>';
    }
}

// Display carrier company after shipping line everywhere (orders and emails)
add_filter( 'woocommerce_get_order_item_totals', 'display_carrier_company_on_order_item_totals', 1000, 3 );
function display_carrier_company_on_order_item_totals( $total_rows, $order, $tax_display ){
    // Load settings and convert them in variables
    extract( carrier_settings() );

    $carrier = $order->get_meta( '_'.$field_id ); // Get carrier company

    if( ! empty($carrier) ) {
        $new_total_rows = [];

        // Loop through order total rows
        foreach( $total_rows as $key => $values ) {
            $new_total_rows[$key] = $values;
            
            // Inserting the carrier company under shipping method
            if( $key === 'shipping' ) {
                $new_total_rows[$field_id] = array(
                    'label' => $label_name,
                    'value' => $carrier,
                );
            }
        }
        return $new_total_rows;
    }
    return $total_rows;
}

All code goes on functions.php file of your active child theme (or theme). Tested and works.


Other related threads:


On cart page (for chosen specific shipping method):

On checkout page page (for chosen specific shipping method):

On customer orders (email notifications and admin order pages too):

这篇关于WooCommerce 购物车和结帐中运输方式的额外承运人字段的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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