Shipping Multiple Addresses
Customers splitting orders across different addresses? One product to Chicago. Another to Miami.
The Shipping Multiple Addresses plugin handles this. Standard exports don’t.
Here’s how to export each product with its own shipping address.
What this code does
It rebuilds your export. Each product gets its own row. Each row shows the exact shipping address for that product.
Export columns include:
- Product Shipping First Name
- Product Shipping Last Name
- Product Shipping Full Name
- Product Shipping Company
- Product Shipping Country
- Product Shipping Address 1
- Product Shipping Address 2
- Product Shipping City
- Product Shipping State
- Product Shipping Postcode
- Product Shipping Note
The complete code
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 |
//this code adds shipping information for each product class WOE_add_product_shipping{ var $qty_shipping, $default_address ; function __construct() { //add fields to export add_filter('woe_get_order_product_fields', array($this,'add_shipping_fields'), 10, 2); //remember QTY+Address for each prodct add_filter('woe_order_export_started',array($this,'fetch_product_shipping'), 10, 1); // rebuild product list based on shipping packages add_filter('woe_fetch_order_products',array($this,'rebuild_products_shipping'), 10, 5); } function add_shipping_fields($fields,$format) { $names = array('first_name','last_name','full_name','company','country','address_1','address_2','city','state','postcode','note'); foreach($names as $f) { $fields['shipping_'.$f] = array('label'=>"Product Shipping ".$f,'checked' => 1, 'colname'=>"Product Shipping ".$f); } return $fields; } function fetch_product_shipping($order_id){ $this->qty_shipping = array(); $shipping_packages = get_post_meta($order_id, '_wcms_packages', true ); if( !is_array($shipping_packages) ) $shipping_packages = array(); foreach($shipping_packages as $pack) { $addr = $pack['destination']; foreach($pack["contents"] as $item) { $key = $item['cart_key']; $addr['full_name'] = trim($addr['first_name'] . " " . $addr['last_name']); // new field $addr['note'] = isset($pack['note']) ? $pack['note'] : ''; if( !isset($this->qty_shipping[$key]) ) $this->qty_shipping[$key] = array(); $this->qty_shipping[$key][] = array("qty"=>$item['quantity'],"address"=>$addr); } } //if no pack! $order = new WC_Order($order_id); $this->default_address = array(); $names = array('first_name','last_name','company','country','address_1','address_2','city','state','postcode'); foreach($names as $field) $this->default_address[$field] = $order->{"get_shipping_".$field}(); $this->default_address['full_name'] = trim($this->default_address['first_name'] . " " . $this->default_address['last_name']); // new field $this->default_address['note'] = $order->get_customer_note(); return $order_id; } function rebuild_products_shipping($products, $order, $labels, $format, $static) { $new_products = array(); foreach( $products as $item_id=>$row) { $item = $order->get_item($item_id); $key = $item['_wcms_cart_key']; if( !isset($this->qty_shipping[$key])) { // not multishipping package! $this->qty_shipping[$key] = array( array("qty"=>$item['qty'], 'address'=>$this->default_address) ); } foreach($this->qty_shipping[$key] as $new_row) { if( isset($row['qty']) ) $row['qty'] = $new_row['qty']; if( isset($row['qty_minus_refund']) ) $row['qty_minus_refund'] = $new_row['qty']; foreach($new_row['address'] as $k=>$v) { $k = 'shipping_'.$k; if( isset($row[$k]) ) $row[$k] = $v; } $new_products[]= $row; } } return $new_products; } } new WOE_add_product_shipping(); |
Setup steps
- Copy the entire code block
- Paste into your theme’s
functions.php - Go to Advanced Order Export for WooCommerce
- Create or edit an export profile
- Open Setup Fields → Products
- You’ll see “Product Shipping” columns. Check the ones you need
- Save and test on an order with multiple shipping addresses
What your export looks like
Order with 2 products going to 2 addresses:
| Product | Qty | Product Shipping Full Name | Product Shipping City | Product Shipping Note |
|---|---|---|---|---|
| Blue Widget | 2 | John Smith | Chicago | Leave at door |
| Red Gadget | 1 | Jane Doe | Miami | Ring bell |
Each product row shows its own address.
When you need this
You sell gifts. Customers buy multiple items. Each goes to a different person.
You run a subscription box. Different products ship to different locations.
You use the Shipping Multiple Addresses plugin. Need to verify address accuracy.
Common mistake
The code expects the _wcms_cart_key meta key. That comes from the Shipping Multiple Addresses plugin.
If that meta key doesn’t exist, the code falls back to the order’s default shipping address.
Products merging incorrectly?
The code splits products by cart_key. Each key represents one shipping package.
If multiple packages ship to the same address, they’ll appear as separate rows. That’s correct behavior.
Pro tip
Need only shipping address columns? Uncheck all other product fields. Export becomes a clean shipping manifest.
Add the “Product Shipping Note” column. Captures special instructions per destination.
Real talk
The Shipping Multiple Addresses plugin stores package data in _wcms_packages post meta. Each package has its own destination and product list.
This code parses that structure. Each product-destination combination becomes one row.
Your fulfillment team gets clear instructions. No more “which product goes where” confusion. Each address gets its own line.