Save and display custom checkout field in WooCommerce

Viewed 211

I have this snippet which shows a CustomPostType on WooCommerce Checkout Page.

function wps_add_select_checkout_field( $checkout ) {
    echo '<h2>'.__('Select a Good Cause').'</h2>';

    $args = array(
        'post_type' => 'good_cause',
        'posts_per_page' => -1,
    );
    $query = new WP_Query($args);

    // Set variable (array)
    $options = array();

    if ( $query->have_posts() ) :
        while ( $query->have_posts() ) : $query->the_post();
            // Add to $options array
            $options[get_the_ID()] = get_the_title();
        endwhile;
        wp_reset_postdata();
     endif;

    woocommerce_form_field( 'daypart', array(
        'type'          => 'select',
        'class'         => array( 'wps-drop' ),
        'label'         => __( 'Delivery options' ),
        'options'       => $options
    ), $checkout->get_value( 'daypart' ));

}
add_action('woocommerce_before_order_notes', 'wps_add_select_checkout_field', 10, 1 );

But this is not stored on the backend, or shown on the email sent to the user or into Order in the user account...

Does anyone know what do I need to add to show this at the backend, display on the emails sent through WP and in the Orders page?

1 Answers

I have also revisited a bit your code. To save your custom checkout field value as custom order meta data and display it on orders and email notifications, use the following:

// Checkout: Display a custom checkout field (dropdown)
add_action( 'woocommerce_before_order_notes', 'wps_add_select_checkout_field' );
function wps_add_select_checkout_field( $checkout ) {
    echo '<h2>'.__('Select a Good Cause').'</h2>';

    $posts = get_posts( array(
        'post_type' => 'good_cause',
        'posts_per_page' => -1,
    ) );

    $options = array(); // Initializing

    foreach ( $posts as $value ) {
        $options[$value->ID] = $value->post_title;
    }

    woocommerce_form_field( 'daypart', array(
        'type'          => 'select',
        'class'         => array( 'wps-drop' ),
        'label'         => __( 'Delivery options' ),
        'options'       => $options,
    ), $checkout->get_value( 'daypart' ));
}

// Save chosen custom field option as custom order meta data
add_action( 'woocommerce_checkout_create_order', 'action_checkout_create_order' );
function action_checkout_create_order( $order ) {
    $key_field = 'daypart';

    if( isset($_POST[$key_field]) && $_POST[$key_field] > 0 ) {
        $post = get_post( intval($_POST[$key_field]) ); // Get the post object from the post ID

        $order->update_meta_data( $key_field, $post->post_title); // Save the post title
        $order->update_meta_data( $key_field.'_id', $post->ID); // Save post ID (optional if needed)
    }
}

// Display on admin orders
add_action( 'woocommerce_admin_order_data_after_shipping_address', 'display_chosen_delivery_on_admin_orders' );
function display_chosen_delivery_on_admin_orders( $order ){
    if( $daypart = $order->get_meta( 'daypart' ) ) {
        $daypart_id = $order->get_meta( 'daypart_id' );
        $daypart_id = empty($daypart_id) ? '' : ' ('. $daypart_id .')';

        // Display the delivery option (post title + post id)
        echo '<p><strong>' . __("Delivery") . ':</strong> ' . $daypart . $daypart_id . '</p>';
    }
}

// Display on customer orders and email notifications
add_filter( 'woocommerce_get_order_item_totals', 'display_delivery_on_order_item_totals', 10, 3 );
function display_delivery_on_order_item_totals( $total_rows, $order, $tax_display ){
    if( $daypart = $order->get_meta( 'daypart' ) ) {
        $new_total_rows = [];

        // Loop through order total rows
        foreach( $total_rows as $key => $values ) {
            // Inserting before payment method
            if( $key === 'payment_method' ) {
                $new_total_rows[$field_id] = array(
                    'label' => __("Delivery", "woocommerce") . ':',
                    'value' => $daypart,
                );
            }
            $new_total_rows[$key] = $values;
        }
        return $new_total_rows;
    }
    return $total_rows;
}

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

Related