Support

Account

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

  • 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;
    }