Support

Account

Home Forums Backend Issues (wp-admin) Add ACF fields as Custom Order Line Item Meta

Solving

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;
    }
Viewing 4 posts - 1 through 4 (of 4 total)

You must be logged in to reply to this topic.