I am currently successfully adding a field to my WooCommerce product pages which is showing the value:
The problem: It isn't showing as a custom field in the admin order "custom fields" Metabox with the value inside it, but just as a text in the order page.
Here is my working code:
// Add the field to the product
add_action('woocommerce_before_add_to_cart_button', 'my_custom_checkout_field');
function my_custom_checkout_field() {
echo '<div id="my_custom_checkout_field"><h3>'.__('My Field').'</h3>';
echo '<label>fill in this field</label> <input type="text" name="my_field_name">';
echo '</div>';
}
// Store custom field
function save_my_custom_checkout_field( $cart_item_data, $product_id ) {
if( isset( $_REQUEST['my_field_name'] ) ) {
$cart_item_data[ 'my_field_name' ] = $_REQUEST['my_field_name'];
/* 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;
}
add_action( 'woocommerce_add_cart_item_data', 'save_my_custom_checkout_field', 10, 2 );
// Render meta on cart and checkout
function render_meta_on_cart_and_checkout( $cart_data, $cart_item = null ) {
$custom_items = array();
/* Woo 2.4.2 updates */
if( !empty( $cart_data ) ) {
$custom_items = $cart_data;
}
if( isset( $cart_item['my_field_name'] ) ) {
$custom_items[] = array( "name" => 'My Field', "value" => $cart_item['my_field_name'] );
}
return $custom_items;
}
add_filter( 'woocommerce_get_item_data', 'render_meta_on_cart_and_checkout', 10, 2 );
// This is what I think needs changing?
function subscription_order_meta_handler( $item_id, $values, $cart_item_key ) {
if( isset( $values['my_field_name'] ) ) {
wc_add_order_item_meta( $item_id, "My Field", $values['my_field_name'] );
}
}
add_action( 'woocommerce_add_order_item_meta', 'subscription_order_meta_handler', 1, 3 );
I think it is this last bit of the code that needs changing. It currently shows the text under the order item, so perhaps I need to adjust wc_add_order_item_meta
to something else?
I've tried everything but it doesn't seem to work. I can get it to work when my field is on the checkout page but not when I pull it from the product page.
Perhaps I am missing a checkout process snippet?
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.
// 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();
}
}
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.