UPDATE 2023 (Still works in Woocommerce 3+)
Firstly, I have gotten everything working as expected, except getting the value for my_field_slug
in the back end "Custom fields" Metabox within Order pages.
Then after a real nightmare, I have found a pretty nice working solution, better than before. In the back end you have now a Custom Metabox with the custom field my_field_slug
displaying the right value, like in this screenshot:

My code is divided into 2 parts.
- The backend Metabox in Order pages, with an editable field showing the correct value coming from a custom field on the product pages (in the front end):
// Adding Meta container admin shop_order pages
add_action( 'add_meta_boxes', 'add_shop_order_meta_boxes' );
if ( ! function_exists( 'add_shop_order_meta_boxes' ) )
{
function add_shop_order_meta_boxes()
{
add_meta_box( 'custom_other_field', __('My Field','woocommerce'), 'add_custom_other_field_content', 'shop_order', 'side', 'core' );
}
}
// Adding Meta field in the meta container on admin shop_order pages
if ( ! function_exists( 'add_custom_other_field_content' ) )
{
function add_custom_other_field_content( $post )
{
$order = wc_get_order($post->ID); // Get the WC_Order object
printf('<p style="border-bottom:solid 1px #eee;padding-bottom:13px;">
<input type="hidden" name="custom_other_field_nonce" value="%s">
<input type="text" style="width:250px;" name="my_field_slug" placeholder="%s" value="%s">
</p>',
wp_create_nonce(),
__('some placeholder text', 'woocommerce'),
$order->get_meta('_my_field_slug')
);
}
}
// Save the Meta field value
add_action( 'woocommerce_process_shop_order_meta', 'save_custom_metabox_field_value', 10, 2 );
if ( ! function_exists( 'save_custom_metabox_field_value' ) )
{
function save_custom_metabox_field_value( $order_id, $post) {
// Check if our nonce is set.
if ( ! isset($_REQUEST['custom_other_field_nonce']) && ! wp_verify_nonce($_REQUEST['custom_other_field_nonce']) ) {
return $order_id;
}
$order = wc_get_order($order_id); // Get the WC_Order object
// Sanitize text input value and update the meta field in the database.
$order->update_meta_data('_my_field_slug', sanitize_text_field($_POST['my_field_slug']));
$order->save();
}
}
- Frontend / Backend:
Note: We allow only one item in cart, as the product field value populates the order Metabox field.
• The product page custom field (front end).
• Displaying this data on cart, checkout and orders (front end). On email notifications too.
• Displaying data on the order page (back end)
// Display a text field on single product pages
add_action('woocommerce_before_add_to_cart_button', 'display_custom_field_on_single_product');
function display_custom_field_on_single_product() {
echo '<div id="my_custom_field">
<label>' . __( 'My Field') . ' </label>
<input type="text" name="my_field_slug" value="">
</div><br>';
}
// Allow only one item in cart
add_filter( 'woocommerce_add_to_cart_validation', 'allow_only_one_cart_item', 10, 3 );
function allow_only_one_cart_item( $passed, $product_id, $quantity ) {
if( ! WC()->cart->is_empty() ) {
WC()->cart->empty_cart();
}
return $passed;
}
// Store custom field value
add_filter( 'woocommerce_add_cart_item_data', 'add_custom_field_as_custom_cart_item_data', 10, 2 );
function add_custom_field_as_custom_cart_item_data( $cart_item_data, $product_id ) {
if( isset( $_REQUEST['my_field_slug'] ) ) {
$cart_item_data[ 'my_field_slug' ] = sanitize_text_field($_REQUEST['my_field_slug']);
// below statement make sure every add to cart action as unique line item
$cart_item_data['unique_key'] = md5( microtime().rand() );
}
return $cart_item_data;
}
// Render the field value on cart and checkout
add_filter( 'woocommerce_get_item_data', 'render_meta_on_cart_and_checkout', 10, 2 );
function render_meta_on_cart_and_checkout( $cart_data, $cart_item = null ) {
$custom_items = array();
if( !empty( $cart_data ) ) {
$custom_items = $cart_data;
}
if( isset( $cart_item['my_field_slug'] ) ) {
$custom_items[] = array(
'name' => __('My Field'),
'value' => $cart_item['my_field_slug']
);
}
return $custom_items;
}
// Save the the custom field value as order custom meta
add_action( 'woocommerce_checkout_create_order', 'save_custom_field_as_order_meta', 10, 2 );
function save_custom_field_as_order_meta( $order, $data ) {
$items = WC()->cart->get_cart();
$item = reset($items);
if ( isset($item['my_field_slug']) ) {
$order->update_meta_data( '_my_field_slug', $item['my_field_slug'] );
}
}
// Save the the custom field value as order item custom meta
add_action( 'woocommerce_checkout_create_order_line_item', 'save_custom_field_as_order_item_meta', 10, 4 );
function save_custom_field_as_order_item_meta( $item, $cart_item_key, $values, $order ) {
if ( isset($values['my_field_slug']) ) {
$item->update_meta_data( 'my_field_slug', $values['my_field_slug'] );
}
}
// Add readable "meta key" label name replacement
add_filter('woocommerce_order_item_display_meta_key', 'filter_wc_order_item_display_meta_key', 10, 3 );
function filter_wc_order_item_display_meta_key( $display_key, $meta, $item ) {
if( $display_key === 'my_field_slug' ) {
$display_key = __('My field', 'woocommerce');
}
return $display_key;
}
Everything is working as expected now.