在订单和电子邮件通知上显示 WooCommerce 自定义结帐字段值

问题描述 投票:0回答:1

我有一些下拉菜单形式的自定义 WooCommerce chekcout 字段。我希望在这些下拉列表中选择的任何选项都显示在管理端的订单详细信息以及订单电子邮件中。但是,我无法让它发挥作用。下拉列表中选择的任何内容都不会显示在电子邮件中或订单详细信息的管理端,这正是我想要的。

我想将下拉列表中的信息保存在订单元数据中,这就是我想用我的代码完成的任务。创建下拉菜单以及根据是否选择送货服务来更改订单总金额是可行的。如果选择取件,则会出现第二个下拉列表,允许客户选择取件位置。这两个下拉列表中的信息应显示在管理端的订单详细信息中,以及显示订单详细信息的任何订单电子邮件中。

我尝试使用 woocommerce_checkout_create_order 在订单创建时将

_delivery_or_pickup
_pickup_location
直接保存到订单元,然后使用 woocommerce_admin_order_data_after_order_details 在 WooCommerce 管理面板中实现最一致的显示。
woocommerce_email_order_meta
挂钩旨在显示管理员和客户电子邮件中的自定义字段。

我的代码如下:

// Add custom fields to the checkout page
add_action('woocommerce_before_order_notes', 'add_delivery_or_pickup_fields');

function add_delivery_or_pickup_fields($checkout) {
    // First dropdown for Delivery or Pickup
    woocommerce_form_field('delivery_or_pickup', array(
        'type' => 'select',
        'class' => array('form-row-wide'),
        'label' => __('Delivery or Pickup?', 'woocommerce'),
        'required' => true,
        'options' => array(
            '' => __('Select an option', 'woocommerce'),
            'delivery' => __('Delivery Service', 'woocommerce'),
            'pickup' => __('Pickup', 'woocommerce')
        ),
    ), $checkout->get_value('delivery_or_pickup'));

    // Second dropdown for pickup location (initially hidden, shown via JavaScript)
    woocommerce_form_field('pickup_location', array(
        'type' => 'select',
        'class' => array('form-row-wide', 'pickup-location-field'), // 'pickup-location-field' class used to control visibility
        'label' => __('Select pickup location:', 'woocommerce'),
        'options' => array(
            '' => __('Select a location', 'woocommerce'),
            'main_office' => __('Pavia 20F - Main Office', 'woocommerce'),
            'kaminis_kitchen' => __('Kamini\'s Kitchen (Baby Beach)', 'woocommerce')
        ),
    ), $checkout->get_value('pickup_location'));

    // JavaScript to toggle visibility of the pickup location dropdown and update delivery fee
    ?>
    <script type="text/javascript">
        jQuery(document).ready(function($) {
            $('.pickup-location-field').hide();

            $('#delivery_or_pickup').change(function() {
                if ($(this).val() === 'pickup') {
                    $('.pickup-location-field').show();
                } else {
                    $('.pickup-location-field').hide();
                }
                
                var deliveryOrPickup = $(this).val();
                $.ajax({
                    type: 'POST',
                    url: wc_checkout_params.ajax_url,
                    data: {
                        action: 'save_delivery_or_pickup_to_session',
                        delivery_or_pickup: deliveryOrPickup,
                    },
                    success: function() {
                        $('body').trigger('update_checkout');
                    }
                });
            }).change();
        });
    </script>
    <?php
}

// Save selection to WooCommerce session
add_action('wp_ajax_save_delivery_or_pickup_to_session', 'save_delivery_or_pickup_to_session');
add_action('wp_ajax_nopriv_save_delivery_or_pickup_to_session', 'save_delivery_or_pickup_to_session');

function save_delivery_or_pickup_to_session() {
    if (isset($_POST['delivery_or_pickup'])) {
        WC()->session->set('delivery_or_pickup', sanitize_text_field($_POST['delivery_or_pickup']));
    }
    wp_die();
}

// Add delivery fee if "Delivery Service" is selected
add_action('woocommerce_cart_calculate_fees', 'add_delivery_fee_based_on_session');

function add_delivery_fee_based_on_session($cart) {
    if (is_admin() && !defined('DOING_AJAX')) return;

    $delivery_or_pickup = WC()->session->get('delivery_or_pickup');

    if ($delivery_or_pickup === 'delivery') {
        $delivery_fee = 10;
        $cart->add_fee(__('Delivery Fee', 'woocommerce'), $delivery_fee);
    }
}

// Save custom fields to order meta on order creation
add_action('woocommerce_checkout_create_order', 'save_delivery_or_pickup_to_order', 10, 2);

function save_delivery_or_pickup_to_order($order, $data) {
    if (!empty($_POST['delivery_or_pickup'])) {
        $order->update_meta_data('_delivery_or_pickup', sanitize_text_field($_POST['delivery_or_pickup']));
    }
    if (!empty($_POST['pickup_location'])) {
        $order->update_meta_data('_pickup_location', sanitize_text_field($_POST['pickup_location']));
    }
}

// Display custom fields in the admin panel under order details
add_action('woocommerce_admin_order_data_after_order_details', 'display_delivery_or_pickup_in_admin_order_meta', 10, 1);

function display_delivery_or_pickup_in_admin_order_meta($order) {
    $delivery_or_pickup = $order->get_meta('_delivery_or_pickup');
    $pickup_location = $order->get_meta('_pickup_location');

    if ($delivery_or_pickup) {
        echo '<p><strong>' . __('Delivery or Pickup') . ':</strong> ' . ($delivery_or_pickup === 'delivery' ? 'Delivery Service' : 'Pickup') . '</p>';
    }
    if ($pickup_location) {
        echo '<p><strong>' . __('Pickup Location') . ':</strong> ' . $pickup_location . '</p>';
    }
}

// Add custom fields to customer and admin emails
add_action('woocommerce_email_order_meta', 'add_delivery_or_pickup_to_emails', 10, 3);

function add_delivery_or_pickup_to_emails($order, $sent_to_admin, $plain_text) {
    $delivery_or_pickup = $order->get_meta('_delivery_or_pickup');
    $pickup_location = $order->get_meta('_pickup_location');

    if ($delivery_or_pickup || $pickup_location) {
        echo '<h2>' . __('Order Details') . '</h2>';
        if ($delivery_or_pickup) {
            echo '<p><strong>' . __('Delivery or Pickup') . ':</strong> ' . ($delivery_or_pickup === 'delivery' ? 'Delivery Service' : 'Pickup') . '</p>';
        }
        if ($pickup_location) {
            echo '<p><strong>' . __('Pickup Location') . ':</strong> ' . $pickup_location . '</p>';
        }
    }
}
woocommerce checkout orders
1个回答
0
投票

它们是你的代码中的一些错误和遗漏的东西......我已经完全修改和优化了你的代码。

在管理订单页面中,在送货地址下方显示您的自定义送货详细信息。

text 1

对于客户订单和电子邮件通知,我在订单详细信息总行表中显示这些自定义运输详细信息。

text 2

尝试以下操作:

// Utility function: Get Delivery or Pickup options
function get_delivery_or_pickup_options() {
    return array(
        ''          => esc_html__( 'Select an option', 'woocommerce' ),
        'delivery'  => esc_html__( 'Delivery Service', 'woocommerce' ),
        'pickup'    => esc_html__( 'Pickup', 'woocommerce' )
    );
}

// Utility function: Get pickup location options
function get_pickup_location_options() {
    return array(
        ''                  => esc_html__( 'Select an option', 'woocommerce' ),
        'main_office'       => esc_html__( 'Pavia 20F - Main Office', 'woocommerce' ),
        'kaminis_kitchen'   => esc_html__( "Kamini's Kitchen (Baby Beach)", 'woocommerce' )
    );
}

// Add custom fields to the checkout page
add_action( 'woocommerce_before_order_notes', 'add_delivery_or_pickup_fields', 10 );
function add_delivery_or_pickup_fields( $checkout ) {
    // 1st dropdown for Delivery or Pickup
    woocommerce_form_field( 'delivery_or_pickup', array(
        'type'      => 'select',
        'class'     => array('form-row-wide'),
        'label'     => esc_html__( 'Delivery or Pickup?', 'woocommerce' ),
        'required'  => true,
        'options'   => get_delivery_or_pickup_options(),
    ), $checkout->get_value('delivery_or_pickup') );

    // 2nd dropdown for pickup location (initially hidden, shown via JavaScript)
    woocommerce_form_field('pickup_location', array(
        'type' => 'select',
        'class' => array('form-row-wide'), // <= Removed additional class
        'label' => __('Select pickup location:', 'woocommerce'),
        'required' => true, // <== Needed as it's a required field when visible
        'options' => get_pickup_location_options(),
    ), $checkout->get_value('pickup_location'));
}

// JavaScript to toggle visibility of the pickup location dropdown and update delivery fee
add_action( 'woocommerce_checkout_init', 'add_delivery_or_pickup_js_script' );
function add_delivery_or_pickup_js_script() {
    // Enqueue jQuery code
    wc_enqueue_js("const pickupField = $('#pickup_location_field');
    // On start
    if ( $('#delivery_or_pickup').val() !== 'pickup' ) {
        pickupField.hide(); // Hide pickup field if hasn't been set on a previous order
    }
    // On change
    $(document.body).on('change', '#delivery_or_pickup', function() { 
        if ( typeof wc_checkout_params === 'undefined' ) {
            return false;
        }
        const deliveryOrPickup = $(this).val();
        deliveryOrPickup === 'pickup' ? pickupField.show() :  pickupField.hide();

        $.ajax({
            type: 'POST',
            url: wc_checkout_params.ajax_url,
            data: {
                action: 'save_delivery_or_pickup_to_session',
                delivery_or_pickup: deliveryOrPickup,
            },
            success: function() {
                $(document.body).trigger('update_checkout');
            }
        });
    });");
    // Ensure to remove the WC Session Variable, if it exists, on checkout page load
    if (  WC()->session->__isset('delivery_or_pickup') ) {
        WC()->session->__unset('delivery_or_pickup');
    }
}

// Ajax request: Save selection to WooCommerce session
add_action('wp_ajax_save_delivery_or_pickup_to_session', 'save_delivery_or_pickup_to_session');
add_action('wp_ajax_nopriv_save_delivery_or_pickup_to_session', 'save_delivery_or_pickup_to_session');
function save_delivery_or_pickup_to_session() {
    if ( isset($_POST['delivery_or_pickup']) ) {
        WC()->session->set('delivery_or_pickup', sanitize_text_field($_POST['delivery_or_pickup']));
    }
    wp_die();
}

// Add delivery fee if "Delivery Service" is selected
add_action( 'woocommerce_cart_calculate_fees', 'add_delivery_option_fee_based_on_session' );
function add_delivery_option_fee_based_on_session( $cart ) {
    if (is_admin() && !defined('DOING_AJAX')) return;

    if ( is_checkout() && WC()->session->get('delivery_or_pickup') === 'delivery' ) {
        $delivery_fee = 10;
        $cart->add_fee( esc_html__( 'Delivery Fee', 'woocommerce' ), $delivery_fee );
    }
}

// Validate custom shipping options
add_action( 'woocommerce_after_checkout_validation', 'delivery_or_pickup_validation', 20, 2 );
function delivery_or_pickup_validation( $data, $errors ) {
    // Delivery or Pickup validation
    if ( isset($_POST['delivery_or_pickup']) && empty($_POST['delivery_or_pickup']) ) {
        $errors->add( 'delivery_or_pickup', esc_html__( 'You must choose between "Delivery" or "Pickup" option.', 'woocommerce' ), 'error' );
    }
    // Pickup location validation
    elseif ( isset($_POST['delivery_or_pickup']) && $_POST['delivery_or_pickup'] === 'pickup' 
    && isset($_POST['pickup_location']) && empty($_POST['pickup_location']) ) {
        $errors->add( 'pickup_location', esc_html__( 'You must choose a pickup location.', 'woocommerce' ), 'error' );
    }
}

// Save custom chosen shipping option details as order metadata
add_action( 'woocommerce_checkout_create_order', 'save_delivery_or_pickup_as_order_metadata', 10 );
function save_delivery_or_pickup_as_order_metadata( $order ) {
    if ( isset($_POST['delivery_or_pickup']) && !empty($_POST['delivery_or_pickup']) ) {
        $order->add_meta_data('_delivery_or_pickup', esc_attr($_POST['delivery_or_pickup']), true );
    }
    if ( isset($_POST['pickup_location']) && !empty($_POST['pickup_location']) ) {
        $order->add_meta_data('_pickup_location', esc_attr($_POST['pickup_location']), true);
    }
    // Remove the WC Session Variable
    WC()->session->__unset('delivery_or_pickup');
}

// Update custom chosen shipping option details as USER metadata (useful for next checkout)
add_action( 'woocommerce_checkout_update_customer', 'save_delivery_or_pickup_as_user_metadata', 10 );
function save_delivery_or_pickup_as_user_metadata( $customer ) {
    if ( isset($_POST['delivery_or_pickup']) && !empty($_POST['delivery_or_pickup']) ) {
        $customer->update_meta_data('delivery_or_pickup', esc_attr($_POST['delivery_or_pickup']));
    }
    if ( isset($_POST['pickup_location']) && !empty($_POST['pickup_location']) ) {
        $customer->update_meta_data('pickup_location', esc_attr($_POST['pickup_location']));
    }
}

// Display chosen custom shipping option details in the admin panel under shipping address
add_action( 'woocommerce_admin_order_data_after_shipping_address', 'display_delivery_or_pickup_meta_in_admin_order', 10 );
function display_delivery_or_pickup_meta_in_admin_order( $order ) {
    // Delivery or Pickup
    if ( $value = $order->get_meta('_delivery_or_pickup') ) {
        $options = get_delivery_or_pickup_options();
        printf( '<p><strong>%s:</strong> %s', esc_html__('Shipping', 'woocommerce' ), $options[$value] );

        // Pickup location
        if ( $value = $order->get_meta('_pickup_location') ) {
            $options = get_pickup_location_options();
            printf( '<br><strong>%s:</strong> %s', esc_html__('Location', 'woocommerce' ), $options[$value] );
        }
        echo '</p>';
    }
}

// Display chosen custom shipping option details in order total lines (customer orders and email notifications)
add_filter( 'woocommerce_get_order_item_totals', 'insert_custom_line_order_item_totals', 10, 3 );
function insert_custom_line_order_item_totals( $total_rows, $order, $tax_display ){
    $shipping = $order->get_meta('_delivery_or_pickup');
    $options1  = get_delivery_or_pickup_options();
    $location = $order->get_meta('_pickup_location');
    $options2  = get_pickup_location_options();
    $key_target = array_key_exists('discount', $total_rows) ? 'discount' : 'cart_subtotal';
    $new_total_rows = array();

    // Loop through total rows
    foreach( $total_rows as $key => $value ){
        $new_total_rows[$key] = $total_rows[$key];

        if( 'cart_subtotal' === $key ) {
            $new_total_rows['shipping2'] = array(
                'label' => esc_html__('Shipping option:'),
                'value' => $options1[$shipping],
            );

            if ( $location ) {
                $new_total_rows['location'] = array(
                    'label' => esc_html__('Pickup location:'),
                    'value' => $options2[$location],
                );
            }

        }
    }
    return $new_total_rows;
}

代码位于子主题的functions.php文件中(或插件中)。

© www.soinside.com 2019 - 2024. All rights reserved.