Local Pickup Plus
Need pickup locations in your exports? Appointment dates? Which items go where?
Local Pickup Plus stores this data differently than standard shipping. Here’s how to export it.
Two scenarios
Scenario 1: One pickup location for the entire order. Customer picks everything up at the same store.
Scenario 2: Multiple pickup locations. Different products go to different stores.
Use the right code for your situation.
Scenario 1: One location per order
This exports pickup details at order level. One row per order.
|
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 76 77 78 79 80 81 82 83 84 85 86 |
// ONE location per order class Woe_Pickup_Location_Fields_to_Order{ var $shipping_info; var $names = array("_pickup_location_id","_pickup_location_name","_pickup_location_address","_pickup_location_phone","_pickup_date","_pickup_items"); function __construct() { add_filter('woe_get_order_fields', array($this,'add_shipping_fields') ); add_filter('woe_settings_validate_defaults', array($this,'hook_new_fields') ); add_filter('woe_order_export_started',array($this,'fetch_order_shipping'), 10, 1); } function add_shipping_fields($fields) { foreach($this->names as $f) { $l = ucwords(trim(str_replace("_"," ",$f))); $fields[$f] = array('label'=>$l,'checked' => 1, 'colname'=>$l); add_filter('woe_get_order_value_'.$f, array($this,'get_shipping_value'), 10, 3 ); } return $fields; } function hook_new_fields($settings) { foreach($this->names as $f) { add_filter('woe_get_order_value_'.$f, array($this,'get_shipping_value'), 10, 3 ); } return $settings; } function fetch_order_shipping($order_id) { //reset values $this->shipping_info = array(); //take 1st ? $order = new WC_Order($order_id); foreach($order->get_items('shipping') as $item_id=>$shipping) { foreach($shipping->get_meta_data() as $meta) { $this->shipping_info[$meta->key] = $meta->value; } break; } // convert some values if( is_array($this->shipping_info['_pickup_location_address']) ) { // MODIFY it? $_parts = array( $this->shipping_info['_pickup_location_address']['address_1'], $this->shipping_info['_pickup_location_address']['address_2'], $this->shipping_info['_pickup_location_address']['city'], $this->shipping_info['_pickup_location_address']['postcode'], $this->shipping_info['_pickup_location_address']['state'], $this->shipping_info['_pickup_location_address']['country'], ); $this->shipping_info['_pickup_location_address'] = join(", ", array_filter($_parts)); } if( is_array($this->shipping_info['_pickup_items']) ){ $items = $order->get_items('line_item'); $item_names = array(); foreach($this->shipping_info['_pickup_items'] as $id) { if(isset($items[$id])) $item_names[] = $items[$id]['name'] . ' x ' . $items[$id]['name']; } $this->shipping_info['_pickup_items'] = join(",", $item_names); } if( !empty($this->shipping_info['_pickup_appointment_start']) ){ $local_pickup_plus = wc_local_pickup_plus(); $appointment = $local_pickup_plus->get_appointments_instance()->get_shipping_item_appointment( $item_id ); if ( $appointment ) { $pickup_date = $appointment->get_start(); $this->shipping_info['_pickup_date'] = esc_html( sprintf( __( '%1$s at %2$s', 'woocommerce' ), date_i18n( wc_date_format(), $pickup_date->getTimestamp() + $pickup_date->getOffset() ), date_i18n( wc_time_format(), $pickup_date->getTimestamp() + $pickup_date->getOffset() ) ) ); } } return $order_id; } function get_shipping_value($value,$order,$field) { if( isset($this->shipping_info[$field]) ) { $value = $this->shipping_info[$field]; } return $value; } } new Woe_Pickup_Location_Fields_to_Order(); |
What you get: One row per order with pickup location ID, name, address, phone, date, and items.
Scenario 2: Location per product
Products might be picked up from different stores. This exports pickup data at product level.
|
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 76 77 78 |
// Location per product class Woe_Pickup_Location_Fields_to_Product{ var $items_shipping_info; function __construct() { add_filter('woe_get_order_product_fields', array($this,'add_shipping_fields') ); add_filter('woe_order_export_started',array($this,'fetch_order_shipping'), 10, 1); add_filter('woe_fetch_order_product',array($this,'fill_item_shipping'), 10, 5); } function add_shipping_fields($fields) { $names = array("_pickup_location_id","_pickup_location_name","_pickup_location_address","_pickup_location_phone","_pickup_date"); foreach($names as $f) { $l = ucwords(trim(str_replace("_"," ",$f))); $fields[$f] = array('label'=>$l,'checked' => 1, 'colname'=>$l); } return $fields; } function fetch_order_shipping($order_id) { //reset $this->items_shipping_info = array(); $order = new WC_Order($order_id); foreach($order->get_items('shipping') as $item_id=>$shipping) { $shipping_info = array(); foreach($shipping->get_meta_data() as $meta) { $shipping_info[$meta->key] = $meta->value; } // convert address if( !empty($shipping_info['_pickup_location_address']) ) { // MODIFY it? $_parts = array( $shipping_info['_pickup_location_address']['address_1'], $shipping_info['_pickup_location_address']['address_2'], $shipping_info['_pickup_location_address']['city'], $shipping_info['_pickup_location_address']['postcode'], $shipping_info['_pickup_location_address']['state'], $shipping_info['_pickup_location_address']['country'], ); $shipping_info['_pickup_location_address'] = join(", ", array_filter($_parts)); } if( !empty($shipping_info['_pickup_appointment_start']) ){ $local_pickup_plus = wc_local_pickup_plus(); $appointment = $local_pickup_plus->get_appointments_instance()->get_shipping_item_appointment( $item_id ); if ( $appointment ) { $pickup_date = $appointment->get_start(); $shipping_info['_pickup_date'] = esc_html( sprintf( __( '%1$s at %2$s', 'woocommerce' ), date_i18n( wc_date_format(), $pickup_date->getTimestamp() + $pickup_date->getOffset() ), date_i18n( wc_time_format(), $pickup_date->getTimestamp() + $pickup_date->getOffset() ) ) ); } } //assign to items if( !empty($shipping_info['_pickup_items']) ) { foreach($shipping_info['_pickup_items'] as $id) $this->items_shipping_info[$id] = $shipping_info; } } return $order_id; } function fill_item_shipping($row, $order, $item, $product, $item_meta) { $id = $item->get_id(); if( isset($this->items_shipping_info[$id]) ) { foreach($this->items_shipping_info[$id] as $k=>$v) if( isset($row[$k])) //field active in export ? $row[$k] = $v; } return $row; } } new Woe_Pickup_Location_Fields_to_Product(); |
What you get: Each product row shows its own pickup location and appointment time.
Setup steps for both scenarios
- Copy your chosen 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
For Scenario 1: Look under Order Fields. You’ll see pickup location columns. Check the ones you need.
For Scenario 2: Look under Product Fields. Pickup columns appear there.
Save and test on one order.
What each field means
_pickup_location_id– Internal ID of the pickup spot_pickup_location_name– Store name or location label_pickup_location_address– Full formatted address_pickup_location_phone– Store phone number_pickup_date– When to pick up (date + time)_pickup_items– Which products are in this pickup
Common mistake
Using the wrong scenario code. If products go to different stores, Scenario 1 will only show one location. You’ll lose data.
Check your Local Pickup Plus settings. “Per order” vs “Per product” matters.
Address looks wrong?
The code combines address parts with commas. Edit the $_parts array if you need different formatting.
Remove address_2 or state by deleting that line. Add company if it exists.
No pickup date?
The date code requires the appointment object. If your orders don’t have appointment times, the _pickup_date field stays empty.
Pro tip
Need both order-level and product-level data? Run two separate export profiles. One with Scenario 1. One with Scenario 2.
Test on an order with multiple pickup locations. Verify each product shows the correct store.
Real talk
Local Pickup Plus stores pickup data in shipping item meta. Not in regular order meta. That’s why standard exports miss it.
These codes dig into the shipping items. Pull out exactly what you need.
Your store staff gets clear pickup instructions. No more guessing which products go to which store.