问题
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