Add New Fields to the Order Details Metabox

I begin to love WooCommerce more and more — yes, it is not so good documented, but it really allows to do very great customizations.

I spend a day creating new beautiful fields you can see on the screenshot below, but I hope this tutorial will help you and you will spend no more than a hour :)

Add custom editable information to the Order Details
Fields added here: text field, radio buttons, dropdown selects (one of them has custom tooltip), textarea and datepicker field!

Everything begins with post Custom Fields values. Let’s call it Order Meta.

Yes, order details are stored in post meta. I added the below values manually, but you can use this tutorial to add the appropriate fields to the checkout page.

WooCommerce order custom fields. Do not forget to turn on this metabox in Screen Options.

Now let’s add these custom fields to the order details metabox.

3 Main Locations: under General Details, under Billing Details and under Shipping Details.

General Details: Input, Textarea, Radio and Select

Actually, using the action hook below, you can add any HTML. But if you add a link with edit_address class and two containers with address and edit_address classes, then, when you click the link, the address container becomes hidden, but the edit_address becomes visible.

Editable order details section

All the code from this post can be added to your current (child) theme functions.php file.

add_action( 'woocommerce_admin_order_data_after_order_details', 'misha_editable_order_meta_general' );

function misha_editable_order_meta_general( $order ){  ?>
		<br class="clear" />
		<h4>Gift Order <a href="#" class="edit_address">Edit</a></h4>
			 * get all the meta data values we need
			$is_gift = get_post_meta( $order->get_id(), 'is_gift', true );
			$gift_wrap = get_post_meta( $order->get_id(), 'gift_wrap', true );
			$gift_name = get_post_meta( $order->get_id(), 'gift_name', true );
			$gift_message = get_post_meta( $order->get_id(), 'gift_message', true );
		<div class="address">
			<p><strong>Is this a gift order?</strong><?php echo $is_gift ? 'Yes' : 'No' ?></p>
				// we show the rest fields in this column only if this order is marked as a gift
				if( $is_gift ) : 
					<p><strong>Gift Wrap:</strong> <?php echo $gift_wrap ?></p>
					<p><strong>Recipient name:</strong> <?php echo $gift_name ?></p>
					<p><strong>Gift message:</strong> <?php echo wpautop( $gift_message ) ?></p>
		<div class="edit_address"><?php
			woocommerce_wp_radio( array(
				'id' => 'is_gift',
				'label' => 'Is this a gift order?',
				'value' => $is_gift,
				'options' => array(
					'' => 'No',
					'1' => 'Yes'
				'style' => 'width:16px', // required for checkboxes and radio buttons
				'wrapper_class' => 'form-field-wide' // always add this class
			) );
			woocommerce_wp_select( array(
				'id' => 'gift_wrap',
				'label' => 'Gift Wrap:',
				'value' => $gift_wrap,
				'options' => array(
					'' => 'No Wrap',
					'Basic Wrap' => 'Basic Wrap',
					'Magic Wrap' => 'Magic Wrap'
				'wrapper_class' => 'form-field-wide'
			) );
			woocommerce_wp_text_input( array(
				'id' => 'gift_name',
				'label' => 'Recipient name:',
				'value' => $gift_name,
				'wrapper_class' => 'form-field-wide'
			) );
			woocommerce_wp_textarea_input( array(
				'id' => 'gift_message',
				'label' => 'Gift message:',
				'value' => $gift_message,
				'wrapper_class' => 'form-field-wide'
			) );
<?php }

add_action( 'woocommerce_process_shop_order_meta', 'misha_save_general_details' );

function misha_save_general_details( $ord_id ){
	update_post_meta( $ord_id, 'is_gift', wc_clean( $_POST[ 'is_gift' ] ) );
	update_post_meta( $ord_id, 'gift_wrap', wc_clean( $_POST[ 'gift_wrap' ] ) );
	update_post_meta( $ord_id, 'gift_name', wc_clean( $_POST[ 'gift_name' ] ) );
	update_post_meta( $ord_id, 'gift_message', wc_sanitize_textarea( $_POST[ 'gift_message' ] ) );
	// wc_clean() and wc_sanitize_textarea() are WooCommerce sanitization functions

So, we have functions:

You can find them all in woocommerce/includes/admin/wc-meta-box-functions.php. Parameters are very similar:

(string) Field ID attribute
(string) Field name attribute. If not set, ID will be used.
(string) Label.
(string) Placeholder.
(string) Field value, that we get from database/cache using get_post_meta(). Should NOT be escaped with esc_attr(), because the function do this itself.
(string) Class or classes of the field.
(string) Class or classes (separated by spaces) for wrapping p element. form-field-wide — fullwidth, if not set – 48% width, left floated.
(string) custom CSS for style attribute of the field itself. For checkboxes and radio buttons always add width:16px because by default they are fullwidth and that looks creepy.
(string) You can add some field description or notes here. Will be shown under the field.
(bool) Very interesting parameter, when set to true the description will be added to a tooltip! We will do it below in this tutorial.
(string) woocommerce_wp_text_input() only! Type of the input field, examples: email,
price, decimal, stock, url, defaults to text.
(integer) woocommerce_wp_textarea_input() only! Textarea cols attribute.
(integer) woocommerce_wp_textarea_input() only! Textarea rows attribute.
(array) For selects and radio buttons. Array of options in array( 'key' => 'value' ) format.

Billing Details. Custom Tooltips.

Everything is very similar to the General Details section, the difference is that you do not need to add Edit link here. We will practice with WooCommerce tooltips here as well.

WooCommerce default tooltips in admin area.
add_action( 'woocommerce_admin_order_data_after_billing_address', 'misha_editable_order_meta_billing' );	 	
function misha_editable_order_meta_billing( $order ){	 	 
	$contactmethod = get_post_meta( $order->get_id(), 'contactmethod', true );
	<div class="address">
		<p<?php if( !$contactmethod ) echo ' class="none_set"' ?>>
			<strong>Preferred Contact Method:</strong>
			<?php echo ( $contactmethod ) ? $contactmethod : 'No contact method selected.' ?>
	<div class="edit_address"><?php
		woocommerce_wp_select( array( 
			'id' => 'contactmethod',
			'label' => 'Preferred Contact Method', 
			'wrapper_class' => 'form-field-wide misha-set-tip-style',
			'value' => $contactmethod,
			'description' => 'Please, contact the customer only with the method selected here.',
			'desc_tip' => true,
			'options' => array(
				'By Phone' => 'By Phone', // option value == option name
				'By Email' => 'By Email'
		) );

add_action( 'woocommerce_process_shop_order_meta', 'misha_save_billing_details' );

function misha_save_billing_details( $ord_id ){
	update_post_meta( $ord_id, 'contactmethod', wc_clean( $_POST[ 'contactmethod' ] ) );

The main problem here is that by default WooCommerce tooltips don’t look very good in this section, but you can easily fix it with the following CSS:

add_action( 'admin_head', 'misha_fix_wc_tooltips' );

function misha_fix_wc_tooltips(){
	echo '<style>
	#order_data .order_data_column .form-field.misha-set-tip-style label{
	.form-field.misha-set-tip-style .woocommerce-help-tip{

Shipping Details. Datepicker Field.

Creating a datepicker field is so simple in WooCommerce. All you need is to pass date-picker class to the woocommerce_wp_text_input() function.

date picker text field in order details woocommerce
add_action( 'woocommerce_admin_order_data_after_shipping_address', 'misha_editable_order_meta_shipping' );

function misha_editable_order_meta_shipping( $order ){

	$shippingdate = get_post_meta( $order->get_id(), 'shippingdate', true );
	<div class="address">
		<p<?php if( empty($shippingdate) ) echo ' class="none_set"' ?>>
 			<strong>Shipping date:</strong>
			<?php echo ( !empty( $shippingdate ) ) ? $shippingdate : 'Anytime.' ?>
	<div class="edit_address"><?php
		woocommerce_wp_text_input( array( 
			'id' => 'shippingdate',
			'label' => 'Shipping date', 
			'wrapper_class' => 'form-field-wide',
			'class' => 'date-picker',
			'style' => 'width:100%',
			'value' => $shippingdate,
			'description' => 'This is the day, when the customer would like to receive his order.'
		) );

add_action( 'woocommerce_process_shop_order_meta', 'misha_save_shipping_details' );

function misha_save_shipping_details( $ord_id ){
	update_post_meta( $ord_id, 'shippingdate', wc_clean( $_POST[ 'shippingdate' ] ) );

That’s all :) If you think I forgot to mention something in this tutorial, please let me know.

Misha Rudrastyh

Misha Rudrastyh

Hey guys and welcome to my website. For more than 10 years I've been doing my best to share with you some superb WordPress guides and tips for free.

Need some developer help? Contact me

Follow me on Twitter