Home › Forums › Backend Issues (wp-admin) › Add ACF fields as Custom Order Line Item Meta
Hello,
How can I add a custom field data as Item meta when the order is saved? Is there anyone who has experience with that?
https://drive.google.com/file/d/1Y_Q8kb1j3BZhLpbuH2OpqQyxL0bvF_MG/view?usp=sharing
I tried the code below but it didn’t help:
add_action( 'woocommerce_checkout_create_order_line_item', 'display_acf_on_orders_and_emails', 10, 4 );
function display_acf_on_orders_and_emails( $item, $cart_item_key, $values, $order ) {
$name = get_field('name', $order_id);
if ( isset($values['name']) ) {
$item->add_meta_data( 'Name', $values['name'] );
}
}
Thank you in advance!
Hi there,
I already made something similar but not with ACF datas.
Maybe you could try something like below.
Let me know if it helps.
Rémi
<?php
// Add custom cart item data when a product is added to cart from product page
add_filter( 'woocommerce_add_cart_item_data', 'my_custom_cart_datas', 10, 3 );
function my_custom_cart_datas( $cart_item_data, $product_id, $variation_id ) {
if( !isset( $_POST['new_post_data'] ) ) {
$cart_item_data['new_post_data'] = get_field('name', $order_id);;
}
return $cart_item_data;
}
// Displaying custom cart datas in cart
add_filter( 'woocommerce_get_item_data', 'my_display_custom_cart_datas', 10, 2 );
function my_display_custom_cart_datas( $item_data, $cart_item_data ) {
if( isset( $cart_item_data['new_post_data'] ) ) {
$item_data[] = array(
'name' => __( 'Displayed key', 'my-text-domain' ),
'value' => wc_clean($cart_item_data['new_post_data'])
);
}
return $item_data;
}
// Add custom meta to item (=product) in order (visible in order in back-end)
add_action( 'woocommerce_checkout_create_order_line_item', 'my_custom_order_line', 10, 4 );
function my_custom_order_line( $item, $cart_item_key, $values, $order ) {
if( isset( $values['new_post_data'] ) ) {
$item->add_meta_data(
'_new_item_line_meta',
$values['new_post_data'],
true
);
}
}
//Modify our custom meta key display
add_filter('woocommerce_order_item_display_meta_key', 'filter_wc_order_item_display_meta_key', 20, 3 );
function filter_wc_order_item_display_meta_key( $display_key, $meta, $item ) {
// Change displayed label for specific order item meta key
if( is_admin() && $item->get_type() === 'line_item' && $meta->key === '_new_item_line_meta' ) {
$display_key = __("Displayed key", "my-text-domain" );
}
return $display_key;
}
// Add custom cart item data to emails
add_filter( 'woocommerce_order_item_name', 'my_custom_data_in_email', 10, 2 );
function my_custom_data_in_email( $product_name, $item ) {
if( isset( $item['new_post_data'] ) ) {
$product_name .= sprintf(
'<ul><li>%s: %s</li></ul>',
__( 'Displayed key', 'my-text-domain' ),
esc_html( $item['_new_item_line_meta'] )
);
}
return $product_name;
}
Thank you Rémi.
I don’t use ACF on products when they are added to the cart, on the regular checkout page, etc. I only use ACF on the Admin order page (Orders > Add new order).
This code seems to be for those who use ACF on the product pages and would like to display them everywhere.
Hi there,
You’re right, my first reply is for front-end orders only.
Could you try the code below.
Let me know if it helps (i could re-use it someday).
Cheers,
Rémi
First, we write a small helper function to get and reorder your acf fields
<?php
//Helper function - Reorder acf datas
function maybe_reorder_acf_fields($order_id) {
$name = get_field('{slug/key}', $order_id) ? get_field('{slug/key}', $order_id) : null; //CHANGE with your own acf slug/key
$start_date = get_field('{slug/key}', $order_id) ? get_field('{slug/key}', $order_id) : null; //CHANGE with your own acf slug/key
$adults = get_field('{slug/key}', $order_id) ? get_field('{slug/key}', $order_id) : null; //CHANGE with your own acf slug/key
$children = get_field('{slug/key}', $order_id) ? get_field('{slug/key}', $order_id) : null; //CHANGE with your own acf slug/key
//Don't remember how datas are validated from get_field() - maybe esc/filter_var functions are useless
$custom_acf_metas = array(
'_acf_tour_customer_name' => esc_html($name),
'_acf_tour_start_date' => esc_html($start_date),
'_acf_tour_adults_nbr' => filter_var($adults, FILTER_SANITIZE_NUMBER_INT),
'_acf_tour_child_nbr' => filter_var($children, FILTER_SANITIZE_NUMBER_INT)
);
return $custom_acf_metas;
}
Next we use WP save_post hook to add OR overwrite custom metas each time an order is saved in backend.
https://developer.wordpress.org/reference/hooks/save_post/
Note : my_save_custom_order_metas() will add your acf datas to all products in an order.
You may adapt this code and probably your acf datas depending on your needs.
<?php
//Add new metas to order item(s)
add_action( 'save_post', 'my_save_custom_order_metas', 10, 3 );
function my_save_custom_order_metas( $order_id, $order, $update ) {
//Not sure if post revisions are used for shop orders - it returns false on a valid $order_id
if ( !is_admin() || get_post_type( $order_id ) !== 'shop_order' || wp_is_post_revision( $order_id ) ) return;
//Uncomment those two lines if you want to target specific order status
// $order_status = $order->get_status();
// if( $order_status !== 'wc-processing' ) return null;
$custom_acf_metas = maybe_reorder_acf_fields($order_id);
//Loop over every items added to your order
if( $order->get_items() ) {
foreach ( $order->get_items() as $item_id => $item ) {
//Nested loop over reordered ACF datas
foreach($custom_acf_metas as $new_meta_key => $new_meta_value) {
//Uncomment the two lines below if you don't want to overwrite your values
//$new_meta_exists = wc_get_order_item_meta( $item_id, $new_meta_key, true);
// if( $new_meta_exists !== false ) continue;
if( $new_meta_value !== null ) {
//Probably not really needed too - could be useful
$new_meta_key = sanitize_key($new_meta_key);
$new_meta_value = sanitize_meta( $new_meta_key, $new_meta_value, 'order_itemmeta' );
//Add new meta
$item->add_meta_data(
$new_meta_key,
$new_meta_value,
true
);
}
}
//Don't forget to save modified order here
$order->save();
}
}
}
Finally we keep our last 2 woocommerce filters to modify back-end display key + email and customer account item details (human readable for both).
<?php
//Modify our custom meta key to make it human readable from back-end
add_filter('woocommerce_order_item_display_meta_key', 'filter_wc_order_item_display_meta_key', 20, 3 );
function filter_wc_order_item_display_meta_key( $display_key, $meta, $item ) {
//Don't know if there is a better way to retrieve $order_id (and related acf datas)
$item_datas = $item->get_data();
$order_id = $item_datas['order_id'];
$custom_acf_metas = maybe_reorder_acf_fields($order_id);
// Change displayed label for specific order item meta key
foreach($custom_acf_metas as $new_meta_key => $new_meta_value) {
switch($new_meta_key) {
case '_acf_tour_customer_name' :
$new_display_key = '[your_display_key]'; //CHANGE with your own value
break;
case '_acf_tour_start_date' :
$new_display_key = '[your_display_key]'; //CHANGE with your own value
break;
case '_acf_tour_adults_nbr' :
$new_display_key = '[your_display_key]'; //CHANGE with your own value
break;
case '_acf_tour_child_nbr' :
$new_display_key = '[your_display_key]'; //CHANGE with your own value
break;
}
//Not sure if is_admin is necessary
if( is_admin() && $item->get_type() === 'line_item' && $meta->key === $new_meta_key ) {
$display_key = __($new_display_key, "my-text-domain" );
}
}
return $display_key;
}
// Add custom cart item data to emails AND customer account order details
add_filter( 'woocommerce_order_item_name', 'my_custom_data_in_email', 10, 2 );
function my_custom_data_in_email( $product_name, $item ) {
$item_datas = $item->get_data();
$order_id = $item_datas['order_id'];
$custom_acf_metas = maybe_reorder_acf_fields($order_id);
// Change displayed label for specific order item meta key
foreach($custom_acf_metas as $new_meta_key => $new_meta_value) {
switch($new_meta_key) {
case '_acf_tour_customer_name' :
$new_display_key = '[your_display_key]'; //CHANGE with your own value
break;
case '_acf_tour_start_date' :
$new_display_key = '[your_display_key]'; //CHANGE with your own value
break;
case '_acf_tour_adults_nbr' :
$new_display_key = '[your_display_key]'; //CHANGE with your own value
break;
case '_acf_tour_child_nbr' :
$new_display_key = '[your_display_key]'; //CHANGE with your own value
break;
}
if( isset( $item[$new_meta_key] ) ) {
$product_name .= sprintf(
'<ul><li>%s: %s</li></ul>',
__( $new_display_key, 'RemSEO' ),
esc_html( $item[$new_meta_key] )
);
}
}
return $product_name;
}
You must be logged in to reply to this topic.
Welcome to the Advanced Custom Fields community forum.
Browse through ideas, snippets of code, questions and answers between fellow ACF users
Helping others is a great way to earn karma, gain badges and help ACF development!
We use cookies to offer you a better browsing experience, analyze site traffic and personalize content. Read about how we use cookies and how you can control them in our Privacy Policy. If you continue to use this site, you consent to our use of cookies.