WooCommerce ShipStation Gateway - Version 4.3.0

Version Description

  • 2022-10-13 =
  • Add - High-Performance Order Storage compatibility.
Download this release

Release Info

Developer harriswong
Plugin Icon 128x128 WooCommerce ShipStation Gateway
Version 4.3.0
Comparing to
See all releases

Code changes from version 4.2.0 to 4.3.0

changelog.txt CHANGED
@@ -1,5 +1,8 @@
1
  *** ShipStation for WooCommerce ***
2
 
 
 
 
3
  = 4.2.0 - 2022-09-07 =
4
  * Add - Filter for manipulating address export data.
5
  * Fix - Remove unnecessary files from plugin zip file.
1
  *** ShipStation for WooCommerce ***
2
 
3
+ = 4.3.0 - 2022-10-13 =
4
+ * Add - High-Performance Order Storage compatibility.
5
+
6
  = 4.2.0 - 2022-09-07 =
7
  * Add - Filter for manipulating address export data.
8
  * Fix - Remove unnecessary files from plugin zip file.
includes/api-requests/class-wc-shipstation-api-export.php CHANGED
@@ -1,14 +1,17 @@
1
  <?php
2
 
3
  if ( ! defined( 'ABSPATH' ) ) {
4
- exit; // Exit if accessed directly
5
  }
6
 
 
 
 
7
  /**
8
  * WC_Shipstation_API_Export Class
9
  */
10
  class WC_Shipstation_API_Export extends WC_Shipstation_API_Request {
11
-
12
  /**
13
  * Constructor
14
  */
@@ -18,6 +21,21 @@ class WC_Shipstation_API_Export extends WC_Shipstation_API_Request {
18
  }
19
  }
20
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
21
  /**
22
  * Do the request
23
  */
@@ -34,9 +52,9 @@ class WC_Shipstation_API_Export extends WC_Shipstation_API_Request {
34
  $tz_offset = get_option( 'gmt_offset' ) * 3600;
35
  $raw_start_date = wc_clean( urldecode( $_GET['start_date'] ) );
36
  $raw_end_date = wc_clean( urldecode( $_GET['end_date'] ) );
37
- $store_weight_unit = get_option('woocommerce_weight_unit');
38
 
39
- // Parse start and end date
40
  if ( $raw_start_date && false === strtotime( $raw_start_date ) ) {
41
  $month = substr( $raw_start_date, 0, 2 );
42
  $day = substr( $raw_start_date, 2, 2 );
@@ -48,17 +66,17 @@ class WC_Shipstation_API_Export extends WC_Shipstation_API_Request {
48
  }
49
 
50
  if ( $raw_end_date && false === strtotime( $raw_end_date ) ) {
51
- $month = substr( $raw_end_date, 0, 2 );
52
- $day = substr( $raw_end_date, 2, 2 );
53
- $year = substr( $raw_end_date, 4, 4 );
54
- $time = substr( $raw_end_date, 9, 4 );
55
- $end_date = gmdate( 'Y-m-d H:i:s', strtotime( $year . '-' . $month . '-' . $day . ' ' . $time ) );
56
  } else {
57
- $end_date = gmdate( 'Y-m-d H:i:s', strtotime( $raw_end_date ) );
58
  }
59
 
60
- if ( version_compare( WC_VERSION, '3.1', '>=' ) ) {
61
- $order_ids = wc_get_orders( array(
62
  'date_modified' => strtotime( $start_date ) . '...' . strtotime( $end_date ),
63
  'type' => 'shop_order',
64
  'status' => WC_ShipStation_Integration::$export_statuses,
@@ -67,72 +85,57 @@ class WC_Shipstation_API_Export extends WC_Shipstation_API_Request {
67
  'order' => 'DESC',
68
  'paged' => $page,
69
  'limit' => WC_SHIPSTATION_EXPORT_LIMIT,
70
- ) );
71
- $order_ids = array_map( function( $order_or_id ) {
72
- return is_a( $order_or_id, 'WC_Order' ) ? $order_or_id->get_id() : $order_or_id;
73
- }, $order_ids );
74
- } else {
75
- $order_ids = $wpdb->get_col(
76
- $wpdb->prepare( "
77
- SELECT ID FROM {$wpdb->posts}
78
- WHERE post_type = 'shop_order'
79
- AND post_status IN ( '" . implode( "','", WC_ShipStation_Integration::$export_statuses ) . "' )
80
- AND %s <= post_modified_gmt
81
- AND post_modified_gmt <= %s
82
- ORDER BY post_modified_gmt DESC
83
- LIMIT %d, %d
84
- ",
85
- $start_date,
86
- $end_date,
87
- WC_SHIPSTATION_EXPORT_LIMIT * ( $page - 1 ),
88
- WC_SHIPSTATION_EXPORT_LIMIT
89
- )
90
- );
91
- }
92
 
93
- // Figure out how to retrieve this using WC Query class.
94
- $max_results = $wpdb->get_var(
95
- $wpdb->prepare( "
96
- SELECT COUNT(ID) FROM {$wpdb->posts}
97
- WHERE post_type = 'shop_order'
98
- AND post_status IN ( '" . implode( "','", WC_ShipStation_Integration::$export_statuses ) . "' )
99
- AND %s <= post_modified_gmt
100
- AND post_modified_gmt <= %s
101
- ",
102
- $start_date,
103
- $end_date
104
  )
105
  );
106
 
 
 
107
  $orders_xml = $xml->createElement( 'Orders' );
108
 
109
- foreach ( $order_ids as $order_id ) {
110
  if ( ! apply_filters( 'woocommerce_shipstation_export_order', true, $order_id ) ) {
111
  continue;
112
  }
113
 
114
- $order = apply_filters( 'woocommerce_shipstation_export_get_order', wc_get_order( $order_id ) );
115
- $order_xml = $xml->createElement( 'Order' );
116
- $wc_gte_30 = version_compare( WC_VERSION, '3.0', '>=' );// gte greater than or equal to 3.0
 
 
 
 
 
 
 
 
 
 
 
117
  $formatted_order_number = ltrim( $order->get_order_number(), '#' );
118
  $this->xml_append( $order_xml, 'OrderNumber', $formatted_order_number );
119
  $this->xml_append( $order_xml, 'OrderID', $order_id );
120
 
121
- if ( $wc_gte_30 ) {
122
- // Sequence of date ordering: date paid > date completed > date created
123
- $order_timestamp = $order->get_date_paid() ?: $order->get_date_completed() ?: $order->get_date_created();
124
- $order_timestamp = $order_timestamp->getOffsetTimestamp();
125
- } else {
126
- $order_timestamp = $order->order_date;
127
- }
128
 
129
- $order_timestamp -= $tz_offset;
130
- $order_status = ( 'refunded' === $order->get_status() ) ? 'cancelled' : $order->get_status();
131
  $this->xml_append( $order_xml, 'OrderDate', gmdate( 'm/d/Y H:i', $order_timestamp ), false );
132
  $this->xml_append( $order_xml, 'OrderStatus', $order_status );
133
- $this->xml_append( $order_xml, 'PaymentMethod', $wc_gte_30 ? $order->get_payment_method() : $order->payment_method );
134
- $this->xml_append( $order_xml, 'OrderPaymentMethodTitle', $wc_gte_30 ? $order->get_payment_method_title() : $order->payment_method_title );
135
- $last_modified = strtotime( $wc_gte_30 ? $order->get_date_modified()->date( 'm/d/Y H:i' ) : $order->modified_date ) - $tz_offset;
136
  $this->xml_append( $order_xml, 'LastModified', gmdate( 'm/d/Y H:i', $last_modified ), false );
137
  $this->xml_append( $order_xml, 'ShippingMethod', implode( ' | ', $this->get_shipping_methods( $order ) ) );
138
 
@@ -144,33 +147,33 @@ class WC_Shipstation_API_Export extends WC_Shipstation_API_Request {
144
  $this->xml_append( $order_xml, 'CostOfGoods', wc_format_decimal( $order->get_meta( '_wc_cog_order_total_cost', true ) ), false );
145
  }
146
 
147
- $this->xml_append( $order_xml, 'ShippingAmount', $wc_gte_30 ? $order->get_shipping_total() : $order->get_total_shipping(), false );
148
- $this->xml_append( $order_xml, 'CustomerNotes', $wc_gte_30 ? $order->get_customer_note() : $order->customer_note );
149
  $this->xml_append( $order_xml, 'InternalNotes', implode( ' | ', $this->get_order_notes( $order ) ) );
150
 
151
- // Custom fields - 1 is used for coupon codes
152
  $this->xml_append( $order_xml, 'CustomField1', implode( ' | ', version_compare( WC_VERSION, '3.7', 'ge' ) ? $order->get_coupon_codes() : $order->get_used_coupons() ) );
153
 
154
- // Custom fields 2 and 3 can be mapped to a custom field via the following filters
155
  $meta_key = apply_filters( 'woocommerce_shipstation_export_custom_field_2', '' );
156
  if ( $meta_key ) {
157
- $this->xml_append( $order_xml, 'CustomField2', apply_filters( 'woocommerce_shipstation_export_custom_field_2_value', get_post_meta( $order_id, $meta_key, true ), $order_id ) );
158
  }
159
 
160
  $meta_key = apply_filters( 'woocommerce_shipstation_export_custom_field_3', '' );
161
  if ( $meta_key ) {
162
- $this->xml_append( $order_xml, 'CustomField3', apply_filters( 'woocommerce_shipstation_export_custom_field_3_value', get_post_meta( $order_id, $meta_key, true ), $order_id ) );
163
  }
164
 
165
  // Customer data.
166
  $customer_xml = $xml->createElement( 'Customer' );
167
- $this->xml_append( $customer_xml, 'CustomerCode', $wc_gte_30 ? $order->get_billing_email() : $order->billing_email );
168
 
169
  $billto_xml = $xml->createElement( 'BillTo' );
170
- $this->xml_append( $billto_xml, 'Name', ( $wc_gte_30 ? $order->get_billing_first_name() : $order->billing_first_name ) . ' ' . ( $wc_gte_30 ? $order->get_billing_last_name() : $order->billing_last_name ) );
171
- $this->xml_append( $billto_xml, 'Company', $wc_gte_30 ? $order->get_billing_company() : $order->billing_company );
172
- $this->xml_append( $billto_xml, 'Phone', $wc_gte_30 ? $order->get_billing_phone() : $order->billing_phone );
173
- $this->xml_append( $billto_xml, 'Email', $wc_gte_30 ? $order->get_billing_email() : $order->billing_email );
174
  $customer_xml->appendChild( $billto_xml );
175
 
176
  $shipto_xml = $xml->createElement( 'ShipTo' );
@@ -190,17 +193,13 @@ class WC_Shipstation_API_Export extends WC_Shipstation_API_Request {
190
 
191
  $order_xml->appendChild( $customer_xml );
192
 
193
- // Item data
194
  $found_item = false;
195
  $items_xml = $xml->createElement( 'Items' );
196
  // Merge arrays without loosing indexes.
197
  $order_items = $order->get_items() + $order->get_items( 'fee' );
198
  foreach ( $order_items as $item_id => $item ) {
199
- if ( $wc_gte_30 ) {
200
- $product = is_callable( array( $item, 'get_product' ) ) ? $item->get_product() : false;
201
- } else {
202
- $product = $order->get_product_from_item( $item );
203
- }
204
  $item_needs_no_shipping = ! $product || ! $product->needs_shipping();
205
  $item_not_a_fee = 'fee' !== $item['type'];
206
  if ( apply_filters( 'woocommerce_shipstation_no_shipping_item', $item_needs_no_shipping && $item_not_a_fee, $product, $item ) ) {
@@ -212,57 +211,45 @@ class WC_Shipstation_API_Export extends WC_Shipstation_API_Request {
212
  $this->xml_append( $item_xml, 'LineItemID', $item_id );
213
 
214
  if ( 'fee' === $item['type'] ) {
215
- $this->xml_append( $item_xml, 'Name', $wc_gte_30 ? $item->get_name() : $item['name'] );
216
  $this->xml_append( $item_xml, 'Quantity', 1, false );
217
  $this->xml_append( $item_xml, 'UnitPrice', $order->get_item_total( $item, false, true ), false );
218
  }
219
 
220
- // handle product specific data
221
  if ( $product && $product->needs_shipping() ) {
222
  $this->xml_append( $item_xml, 'SKU', $product->get_sku() );
223
  $this->xml_append( $item_xml, 'Name', $product->get_title() );
224
- // image data
225
- $image_id = $product->get_image_id();
226
  $image_url = $image_id ? current( wp_get_attachment_image_src( $image_id, 'woocommerce_gallery_thumbnail' ) ) : '';
227
  $this->xml_append( $item_xml, 'ImageUrl', $image_url );
228
 
229
  if ( 'kg' === $store_weight_unit ) {
230
  $this->xml_append( $item_xml, 'Weight', wc_get_weight( $product->get_weight(), 'g' ), false );
231
- $this->xml_append( $item_xml, 'WeightUnits', 'Grams', false );
232
  } else {
233
  $this->xml_append( $item_xml, 'Weight', $product->get_weight(), false );
234
  $this->xml_append( $item_xml, 'WeightUnits', $this->get_shipstation_weight_units( $store_weight_unit ), false );
235
  }
236
 
237
- // current item quantity - refunded quantity
238
  $item_qty = $item['qty'] - abs( $order->get_qty_refunded_for_item( $item_id ) );
239
  $this->xml_append( $item_xml, 'Quantity', $item_qty, false );
240
  $this->xml_append( $item_xml, 'UnitPrice', $order->get_item_subtotal( $item, false, true ), false );
241
  }
242
 
243
  if ( $item['item_meta'] ) {
244
- if ( version_compare( WC_VERSION, '3.0.0', '<' ) ) {
245
- $item_meta = new WC_Order_Item_Meta( $item, $product );
246
- $formatted_meta = $item_meta->get_formatted( '_' );
247
- } else {
248
- add_filter( 'woocommerce_is_attribute_in_product_name', '__return_false' );
249
- $formatted_meta = $item->get_formatted_meta_data();
250
- }
251
 
252
  if ( ! empty( $formatted_meta ) ) {
253
  $options_xml = $xml->createElement( 'Options' );
254
 
255
  foreach ( $formatted_meta as $meta_key => $meta ) {
256
- $option_xml = $xml->createElement( 'Option' );
257
-
258
- if ( version_compare( WC_VERSION, '3.0.0', '<' ) ) {
259
- $this->xml_append( $option_xml, 'Name', $meta['label'] );
260
- $this->xml_append( $option_xml, 'Value', $meta['value'] );
261
- } else {
262
- $this->xml_append( $option_xml, 'Name', $meta->display_key );
263
- $this->xml_append( $option_xml, 'Value', wp_strip_all_tags( $meta->display_value ) );
264
- }
265
-
266
  $options_xml->appendChild( $option_xml );
267
  }
268
 
@@ -277,9 +264,9 @@ class WC_Shipstation_API_Export extends WC_Shipstation_API_Request {
277
  continue;
278
  }
279
 
280
- // Append cart level discount line
281
  if ( $order->get_total_discount() ) {
282
- $item_xml = $xml->createElement( 'Item' );
283
  $this->xml_append( $item_xml, 'SKU', 'total-discount' );
284
  $this->xml_append( $item_xml, 'Name', __( 'Total Discount', 'woocommerce-shipstation-integration' ) );
285
  $this->xml_append( $item_xml, 'Adjustment', 'true', false );
@@ -288,16 +275,17 @@ class WC_Shipstation_API_Export extends WC_Shipstation_API_Request {
288
  $items_xml->appendChild( $item_xml );
289
  }
290
 
291
- // Append items XML
292
  $order_xml->appendChild( $items_xml );
293
  $orders_xml->appendChild( apply_filters( 'woocommerce_shipstation_export_order_xml', $order_xml ) );
294
 
295
  $exported ++;
296
 
297
  // Add order note to indicate it has been exported to Shipstation.
298
- if ( 'yes' !== get_post_meta( $order_id, '_shipstation_exported', true ) ) {
299
  $order->add_order_note( __( 'Order has been exported to Shipstation', 'woocommerce-shipstation-integration' ) );
300
- update_post_meta( $order_id, '_shipstation_exported', 'yes' );
 
301
  }
302
  }
303
 
@@ -318,53 +306,54 @@ class WC_Shipstation_API_Export extends WC_Shipstation_API_Request {
318
  * @result array.
319
  */
320
  public function get_address_data( $order ) {
321
- $wc_gte_30 = version_compare( WC_VERSION, '3.0', '>=' );// gte greater than or equal to 3.0.
322
- $shipping_country = $wc_gte_30 ? $order->get_shipping_country() : $order->shipping_country;
323
- $shipping_address = $wc_gte_30 ? $order->get_shipping_address_1() : $order->shipping_address_1;
324
 
325
  $address = array();
326
 
327
  if ( empty( $shipping_country ) && empty( $shipping_address ) ) {
328
- $name = ( $wc_gte_30 ? $order->get_billing_first_name() : $order->billing_first_name ) . ' ' . ( $wc_gte_30 ? $order->get_billing_last_name() : $order->billing_last_name );
329
 
330
  $address['name'] = $name;
331
- $address['company'] = $wc_gte_30 ? $order->get_billing_company() : $order->billing_company;
332
- $address['address1'] = $wc_gte_30 ? $order->get_billing_address_1() : $order->billing_address_1;
333
- $address['address2'] = $wc_gte_30 ? $order->get_billing_address_2() : $order->billing_address_2;
334
- $address['city'] = $wc_gte_30 ? $order->get_billing_city() : $order->billing_city;
335
- $address['state'] = $wc_gte_30 ? $order->get_billing_state() : $order->billing_state;
336
- $address['postcode'] = $wc_gte_30 ? $order->get_billing_postcode() : $order->billing_postcode;
337
- $address['country'] = $wc_gte_30 ? $order->get_billing_country() : $order->billing_country;
338
- $address['phone'] = $wc_gte_30 ? $order->get_billing_phone() : $order->billing_phone;
339
  } else {
340
- $name = ( $wc_gte_30 ? $order->get_shipping_first_name() : $order->shipping_first_name ) . ' ' . ( $wc_gte_30 ? $order->get_shipping_last_name() : $order->shipping_last_name );
341
 
342
  $address['name'] = $name;
343
- $address['company'] = $wc_gte_30 ? $order->get_shipping_company() : $order->shipping_company;
344
- $address['address1'] = $wc_gte_30 ? $order->get_shipping_address_1() : $order->shipping_address_1;
345
- $address['address2'] = $wc_gte_30 ? $order->get_shipping_address_2() : $order->shipping_address_2;
346
- $address['city'] = $wc_gte_30 ? $order->get_shipping_city() : $order->shipping_city;
347
- $address['state'] = $wc_gte_30 ? $order->get_shipping_state() : $order->shipping_state;
348
- $address['postcode'] = $wc_gte_30 ? $order->get_shipping_postcode() : $order->shipping_postcode;
349
- $address['country'] = $wc_gte_30 ? $order->get_shipping_country() : $order->shipping_country;
350
- $address['phone'] = $wc_gte_30 ? $order->get_billing_phone() : $order->billing_phone;
351
  }
352
 
353
- return apply_filters( 'woocommerce_shipstation_export_address_data', $address, $order, $wc_gte_30 );
354
  }
355
 
356
  /**
357
  * Get shipping method names
358
- * @param WC_Order $order
 
 
359
  * @return array
360
  */
361
  private function get_shipping_methods( $order ) {
362
- $shipping_methods = $order->get_shipping_methods();
363
  $shipping_method_names = array();
364
 
365
  foreach ( $shipping_methods as $shipping_method ) {
366
- // Replace non-AlNum characters with space
367
- $method_name = preg_replace( '/[^A-Za-z0-9 \-\.\_,]/', '', $shipping_method['name'] );
368
  $shipping_method_names[] = $method_name;
369
  }
370
 
@@ -373,20 +362,19 @@ class WC_Shipstation_API_Export extends WC_Shipstation_API_Request {
373
 
374
  /**
375
  * Get Order Notes
376
- * @param WC_Order $order
 
377
  * @return array
378
  */
379
  private function get_order_notes( $order ) {
380
  $args = array(
381
- 'post_id' => version_compare( WC_VERSION, '3.0.0', '>=' ) ? $order->get_id() : $order->id,
382
  'approve' => 'approve',
383
  'type' => 'order_note',
384
  );
385
 
386
  remove_filter( 'comments_clauses', array( 'WC_Comments', 'exclude_order_comments' ), 10, 1 );
387
-
388
  $notes = get_comments( $args );
389
-
390
  add_filter( 'comments_clauses', array( 'WC_Comments', 'exclude_order_comments' ), 10, 1 );
391
 
392
  $order_notes = array();
@@ -405,13 +393,13 @@ class WC_Shipstation_API_Export extends WC_Shipstation_API_Request {
405
  */
406
  private function xml_append( $append_to, $name, $value, $cdata = true ) {
407
  $data = $append_to->appendChild( $append_to->ownerDocument->createElement( $name ) );
408
-
409
  if ( $cdata ) {
410
  $child_node = empty( $append_to->ownerDocument->createCDATASection( $value ) ) ? $append_to->ownerDocument->createCDATASection( '' ) : $append_to->ownerDocument->createCDATASection( $value );
411
  } else {
412
  $child_node = empty( $append_to->ownerDocument->createTextNode( $value ) ) ? $append_to->ownerDocument->createTextNode( '' ) : $append_to->ownerDocument->createTextNode( $value );
413
  }
414
-
415
  $data->appendChild( $child_node );
416
  }
417
 
@@ -419,7 +407,7 @@ class WC_Shipstation_API_Export extends WC_Shipstation_API_Request {
419
  * Convert weight unit abbreviation to Shipstation enum (Pounds, Ounces, Grams)
420
  */
421
  private function get_shipstation_weight_units( $unit_abbreviation ) {
422
- switch( $unit_abbreviation ) {
423
  case 'lbs':
424
  return 'Pounds';
425
  case 'oz':
1
  <?php
2
 
3
  if ( ! defined( 'ABSPATH' ) ) {
4
+ exit; // Exit if accessed directly.
5
  }
6
 
7
+ use WooCommerce\ShipStation\Order_Util;
8
+ use Automattic\WooCommerce\Internal\DataStores\Orders\OrdersTableDataStore;
9
+
10
  /**
11
  * WC_Shipstation_API_Export Class
12
  */
13
  class WC_Shipstation_API_Export extends WC_Shipstation_API_Request {
14
+ use Order_Util;
15
  /**
16
  * Constructor
17
  */
21
  }
22
  }
23
 
24
+ private static function prepare_in( $values ) {
25
+ return implode(
26
+ ',',
27
+ array_map(
28
+ function ( $value ) {
29
+ global $wpdb;
30
+
31
+ // Use the official prepare() function to sanitize the value.
32
+ return $wpdb->prepare( '%s', $value );
33
+ },
34
+ $values
35
+ )
36
+ );
37
+ }
38
+
39
  /**
40
  * Do the request
41
  */
52
  $tz_offset = get_option( 'gmt_offset' ) * 3600;
53
  $raw_start_date = wc_clean( urldecode( $_GET['start_date'] ) );
54
  $raw_end_date = wc_clean( urldecode( $_GET['end_date'] ) );
55
+ $store_weight_unit = get_option( 'woocommerce_weight_unit' );
56
 
57
+ // Parse start and end date.
58
  if ( $raw_start_date && false === strtotime( $raw_start_date ) ) {
59
  $month = substr( $raw_start_date, 0, 2 );
60
  $day = substr( $raw_start_date, 2, 2 );
66
  }
67
 
68
  if ( $raw_end_date && false === strtotime( $raw_end_date ) ) {
69
+ $month = substr( $raw_end_date, 0, 2 );
70
+ $day = substr( $raw_end_date, 2, 2 );
71
+ $year = substr( $raw_end_date, 4, 4 );
72
+ $time = substr( $raw_end_date, 9, 4 );
73
+ $end_date = gmdate( 'Y-m-d H:i:s', strtotime( $year . '-' . $month . '-' . $day . ' ' . $time ) );
74
  } else {
75
+ $end_date = gmdate( 'Y-m-d H:i:s', strtotime( $raw_end_date ) );
76
  }
77
 
78
+ $orders_to_export = wc_get_orders(
79
+ array(
80
  'date_modified' => strtotime( $start_date ) . '...' . strtotime( $end_date ),
81
  'type' => 'shop_order',
82
  'status' => WC_ShipStation_Integration::$export_statuses,
85
  'order' => 'DESC',
86
  'paged' => $page,
87
  'limit' => WC_SHIPSTATION_EXPORT_LIMIT,
88
+ )
89
+ );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
90
 
91
+ $total_orders_to_export = wc_get_orders(
92
+ array(
93
+ 'type' => 'shop_order',
94
+ 'date_modified' => strtotime( $start_date ) . '...' . strtotime( $end_date ),
95
+ 'status' => WC_ShipStation_Integration::$export_statuses,
96
+ 'paginate' => true,
97
+ 'return' => 'ids',
 
 
 
 
98
  )
99
  );
100
 
101
+ $max_results = $total_orders_to_export->total;
102
+
103
  $orders_xml = $xml->createElement( 'Orders' );
104
 
105
+ foreach ( $orders_to_export as $order_id ) {
106
  if ( ! apply_filters( 'woocommerce_shipstation_export_order', true, $order_id ) ) {
107
  continue;
108
  }
109
 
110
+ /**
111
+ * WooCommerce Order.
112
+ *
113
+ * @var WC_Order $order
114
+ */
115
+ $order = apply_filters( 'woocommerce_shipstation_export_get_order', wc_get_order( $order_id ) );
116
+
117
+ if ( ! self::is_wc_order( $order ) ) {
118
+ /* translators: 1: order id */
119
+ $this->log( sprintf( __( 'Order %s can not be found.', 'woocommerce-shipstation-integration' ), $order_id ) );
120
+ continue;
121
+ }
122
+
123
+ $order_xml = $xml->createElement( 'Order' );
124
  $formatted_order_number = ltrim( $order->get_order_number(), '#' );
125
  $this->xml_append( $order_xml, 'OrderNumber', $formatted_order_number );
126
  $this->xml_append( $order_xml, 'OrderID', $order_id );
127
 
128
+ // Sequence of date ordering: date paid > date completed > date created.
129
+ $order_timestamp = $order->get_date_paid() ?: $order->get_date_completed() ?: $order->get_date_created();
130
+ $order_timestamp = $order_timestamp->getOffsetTimestamp();
 
 
 
 
131
 
132
+ $order_timestamp -= $tz_offset;
133
+ $order_status = ( 'refunded' === $order->get_status() ) ? 'cancelled' : $order->get_status();
134
  $this->xml_append( $order_xml, 'OrderDate', gmdate( 'm/d/Y H:i', $order_timestamp ), false );
135
  $this->xml_append( $order_xml, 'OrderStatus', $order_status );
136
+ $this->xml_append( $order_xml, 'PaymentMethod', $order->get_payment_method() );
137
+ $this->xml_append( $order_xml, 'OrderPaymentMethodTitle', $order->get_payment_method_title() );
138
+ $last_modified = strtotime( $order->get_date_modified()->date( 'm/d/Y H:i' ) ) - $tz_offset;
139
  $this->xml_append( $order_xml, 'LastModified', gmdate( 'm/d/Y H:i', $last_modified ), false );
140
  $this->xml_append( $order_xml, 'ShippingMethod', implode( ' | ', $this->get_shipping_methods( $order ) ) );
141
 
147
  $this->xml_append( $order_xml, 'CostOfGoods', wc_format_decimal( $order->get_meta( '_wc_cog_order_total_cost', true ) ), false );
148
  }
149
 
150
+ $this->xml_append( $order_xml, 'ShippingAmount', $order->get_shipping_total(), false );
151
+ $this->xml_append( $order_xml, 'CustomerNotes', $order->get_customer_note() );
152
  $this->xml_append( $order_xml, 'InternalNotes', implode( ' | ', $this->get_order_notes( $order ) ) );
153
 
154
+ // Custom fields - 1 is used for coupon codes.
155
  $this->xml_append( $order_xml, 'CustomField1', implode( ' | ', version_compare( WC_VERSION, '3.7', 'ge' ) ? $order->get_coupon_codes() : $order->get_used_coupons() ) );
156
 
157
+ // Custom fields 2 and 3 can be mapped to a custom field via the following filters.
158
  $meta_key = apply_filters( 'woocommerce_shipstation_export_custom_field_2', '' );
159
  if ( $meta_key ) {
160
+ $this->xml_append( $order_xml, 'CustomField2', apply_filters( 'woocommerce_shipstation_export_custom_field_2_value', $order->get_meta( $meta_key, true ), $order_id ) );
161
  }
162
 
163
  $meta_key = apply_filters( 'woocommerce_shipstation_export_custom_field_3', '' );
164
  if ( $meta_key ) {
165
+ $this->xml_append( $order_xml, 'CustomField3', apply_filters( 'woocommerce_shipstation_export_custom_field_3_value', $order->get_meta( $meta_key, true ), $order_id ) );
166
  }
167
 
168
  // Customer data.
169
  $customer_xml = $xml->createElement( 'Customer' );
170
+ $this->xml_append( $customer_xml, 'CustomerCode', $order->get_billing_email() );
171
 
172
  $billto_xml = $xml->createElement( 'BillTo' );
173
+ $this->xml_append( $billto_xml, 'Name', $order->get_billing_first_name() . ' ' . $order->get_billing_last_name() );
174
+ $this->xml_append( $billto_xml, 'Company', $order->get_billing_company() );
175
+ $this->xml_append( $billto_xml, 'Phone', $order->get_billing_phone() );
176
+ $this->xml_append( $billto_xml, 'Email', $order->get_billing_email() );
177
  $customer_xml->appendChild( $billto_xml );
178
 
179
  $shipto_xml = $xml->createElement( 'ShipTo' );
193
 
194
  $order_xml->appendChild( $customer_xml );
195
 
196
+ // Item data.
197
  $found_item = false;
198
  $items_xml = $xml->createElement( 'Items' );
199
  // Merge arrays without loosing indexes.
200
  $order_items = $order->get_items() + $order->get_items( 'fee' );
201
  foreach ( $order_items as $item_id => $item ) {
202
+ $product = is_callable( array( $item, 'get_product' ) ) ? $item->get_product() : false;
 
 
 
 
203
  $item_needs_no_shipping = ! $product || ! $product->needs_shipping();
204
  $item_not_a_fee = 'fee' !== $item['type'];
205
  if ( apply_filters( 'woocommerce_shipstation_no_shipping_item', $item_needs_no_shipping && $item_not_a_fee, $product, $item ) ) {
211
  $this->xml_append( $item_xml, 'LineItemID', $item_id );
212
 
213
  if ( 'fee' === $item['type'] ) {
214
+ $this->xml_append( $item_xml, 'Name', $item->get_name() );
215
  $this->xml_append( $item_xml, 'Quantity', 1, false );
216
  $this->xml_append( $item_xml, 'UnitPrice', $order->get_item_total( $item, false, true ), false );
217
  }
218
 
219
+ // handle product specific data.
220
  if ( $product && $product->needs_shipping() ) {
221
  $this->xml_append( $item_xml, 'SKU', $product->get_sku() );
222
  $this->xml_append( $item_xml, 'Name', $product->get_title() );
223
+ // image data.
224
+ $image_id = $product->get_image_id();
225
  $image_url = $image_id ? current( wp_get_attachment_image_src( $image_id, 'woocommerce_gallery_thumbnail' ) ) : '';
226
  $this->xml_append( $item_xml, 'ImageUrl', $image_url );
227
 
228
  if ( 'kg' === $store_weight_unit ) {
229
  $this->xml_append( $item_xml, 'Weight', wc_get_weight( $product->get_weight(), 'g' ), false );
230
+ $this->xml_append( $item_xml, 'WeightUnits', 'Grams', false );
231
  } else {
232
  $this->xml_append( $item_xml, 'Weight', $product->get_weight(), false );
233
  $this->xml_append( $item_xml, 'WeightUnits', $this->get_shipstation_weight_units( $store_weight_unit ), false );
234
  }
235
 
236
+ // current item quantity - refunded quantity.
237
  $item_qty = $item['qty'] - abs( $order->get_qty_refunded_for_item( $item_id ) );
238
  $this->xml_append( $item_xml, 'Quantity', $item_qty, false );
239
  $this->xml_append( $item_xml, 'UnitPrice', $order->get_item_subtotal( $item, false, true ), false );
240
  }
241
 
242
  if ( $item['item_meta'] ) {
243
+ add_filter( 'woocommerce_is_attribute_in_product_name', '__return_false' );
244
+ $formatted_meta = $item->get_formatted_meta_data();
 
 
 
 
 
245
 
246
  if ( ! empty( $formatted_meta ) ) {
247
  $options_xml = $xml->createElement( 'Options' );
248
 
249
  foreach ( $formatted_meta as $meta_key => $meta ) {
250
+ $option_xml = $xml->createElement( 'Option' );
251
+ $this->xml_append( $option_xml, 'Name', $meta->display_key );
252
+ $this->xml_append( $option_xml, 'Value', wp_strip_all_tags( $meta->display_value ) );
 
 
 
 
 
 
 
253
  $options_xml->appendChild( $option_xml );
254
  }
255
 
264
  continue;
265
  }
266
 
267
+ // Append cart level discount line.
268
  if ( $order->get_total_discount() ) {
269
+ $item_xml = $xml->createElement( 'Item' );
270
  $this->xml_append( $item_xml, 'SKU', 'total-discount' );
271
  $this->xml_append( $item_xml, 'Name', __( 'Total Discount', 'woocommerce-shipstation-integration' ) );
272
  $this->xml_append( $item_xml, 'Adjustment', 'true', false );
275
  $items_xml->appendChild( $item_xml );
276
  }
277
 
278
+ // Append items XML.
279
  $order_xml->appendChild( $items_xml );
280
  $orders_xml->appendChild( apply_filters( 'woocommerce_shipstation_export_order_xml', $order_xml ) );
281
 
282
  $exported ++;
283
 
284
  // Add order note to indicate it has been exported to Shipstation.
285
+ if ( 'yes' !== $order->get_meta( '_shipstation_exported', true ) ) {
286
  $order->add_order_note( __( 'Order has been exported to Shipstation', 'woocommerce-shipstation-integration' ) );
287
+ $order->update_meta_data( '_shipstation_exported', 'yes' );
288
+ $order->save();
289
  }
290
  }
291
 
306
  * @result array.
307
  */
308
  public function get_address_data( $order ) {
309
+ $shipping_country = $order->get_shipping_country();
310
+ $shipping_address = $order->get_shipping_address_1();
 
311
 
312
  $address = array();
313
 
314
  if ( empty( $shipping_country ) && empty( $shipping_address ) ) {
315
+ $name = $order->get_billing_first_name() . ' ' . $order->get_billing_last_name();
316
 
317
  $address['name'] = $name;
318
+ $address['company'] = $order->get_billing_company();
319
+ $address['address1'] = $order->get_billing_address_1();
320
+ $address['address2'] = $order->get_billing_address_2();
321
+ $address['city'] = $order->get_billing_city();
322
+ $address['state'] = $order->get_billing_state();
323
+ $address['postcode'] = $order->get_billing_postcode();
324
+ $address['country'] = $order->get_billing_country();
325
+ $address['phone'] = $order->get_billing_phone();
326
  } else {
327
+ $name = $order->get_shipping_first_name() . ' ' . $order->get_shipping_last_name();
328
 
329
  $address['name'] = $name;
330
+ $address['company'] = $order->get_shipping_company();
331
+ $address['address1'] = $order->get_shipping_address_1();
332
+ $address['address2'] = $order->get_shipping_address_2();
333
+ $address['city'] = $order->get_shipping_city();
334
+ $address['state'] = $order->get_shipping_state();
335
+ $address['postcode'] = $order->get_shipping_postcode();
336
+ $address['country'] = $order->get_shipping_country();
337
+ $address['phone'] = $order->get_billing_phone();
338
  }
339
 
340
+ return apply_filters( 'woocommerce_shipstation_export_address_data', $address, $order, true );
341
  }
342
 
343
  /**
344
  * Get shipping method names
345
+ *
346
+ * @param WC_Order $order Order object.
347
+ *
348
  * @return array
349
  */
350
  private function get_shipping_methods( $order ) {
351
+ $shipping_methods = $order->get_shipping_methods();
352
  $shipping_method_names = array();
353
 
354
  foreach ( $shipping_methods as $shipping_method ) {
355
+ // Replace non-AlNum characters with space.
356
+ $method_name = preg_replace( '/[^A-Za-z0-9 \-\.\_,]/', '', $shipping_method['name'] );
357
  $shipping_method_names[] = $method_name;
358
  }
359
 
362
 
363
  /**
364
  * Get Order Notes
365
+ *
366
+ * @param WC_Order $order Order object.
367
  * @return array
368
  */
369
  private function get_order_notes( $order ) {
370
  $args = array(
371
+ 'post_id' => $order->get_id(),
372
  'approve' => 'approve',
373
  'type' => 'order_note',
374
  );
375
 
376
  remove_filter( 'comments_clauses', array( 'WC_Comments', 'exclude_order_comments' ), 10, 1 );
 
377
  $notes = get_comments( $args );
 
378
  add_filter( 'comments_clauses', array( 'WC_Comments', 'exclude_order_comments' ), 10, 1 );
379
 
380
  $order_notes = array();
393
  */
394
  private function xml_append( $append_to, $name, $value, $cdata = true ) {
395
  $data = $append_to->appendChild( $append_to->ownerDocument->createElement( $name ) );
396
+
397
  if ( $cdata ) {
398
  $child_node = empty( $append_to->ownerDocument->createCDATASection( $value ) ) ? $append_to->ownerDocument->createCDATASection( '' ) : $append_to->ownerDocument->createCDATASection( $value );
399
  } else {
400
  $child_node = empty( $append_to->ownerDocument->createTextNode( $value ) ) ? $append_to->ownerDocument->createTextNode( '' ) : $append_to->ownerDocument->createTextNode( $value );
401
  }
402
+
403
  $data->appendChild( $child_node );
404
  }
405
 
407
  * Convert weight unit abbreviation to Shipstation enum (Pounds, Ounces, Grams)
408
  */
409
  private function get_shipstation_weight_units( $unit_abbreviation ) {
410
+ switch ( $unit_abbreviation ) {
411
  case 'lbs':
412
  return 'Pounds';
413
  case 'oz':
includes/api-requests/class-wc-shipstation-api-shipnotify.php CHANGED
@@ -1,7 +1,7 @@
1
  <?php
2
 
3
  if ( ! defined( 'ABSPATH' ) ) {
4
- exit; // Exit if accessed directly
5
  }
6
 
7
  /**
@@ -30,11 +30,7 @@ class WC_Shipstation_API_Shipnotify extends WC_Shipstation_API_Request {
30
 
31
  foreach ( $order->get_items() as $item_id => $item ) {
32
 
33
- if ( version_compare( WC_VERSION, '3.0', '>=' ) ) {
34
- $product = is_callable( array( $item, 'get_product' ) ) ? $item->get_product() : false;
35
- } else {
36
- $product = $order->get_product_from_item( $item );
37
- }
38
 
39
  if ( is_a( $product, 'WC_Product' ) && $product->needs_shipping() ) {
40
  $needs_shipping += ( $item['qty'] - abs( $order->get_qty_refunded_for_item( $item_id ) ) );
@@ -56,27 +52,10 @@ class WC_Shipstation_API_Shipnotify extends WC_Shipstation_API_Request {
56
  * @return bool Returns true if item is shippable product.
57
  */
58
  private function is_shippable_item( $order, $item_id ) {
59
- if ( version_compare( WC_VERSION, '3.0', '>=' ) ) {
60
- $item = $order->get_item( $item_id );
61
- if ( ! is_callable( array( $item, 'get_product' ) ) ) {
62
- return false;
63
- }
64
-
65
- $product = $item->get_product();
66
- } else {
67
- $items = $order->get_items();
68
- if ( ! isset( $items[ $item_id ] ) ) {
69
- return false;
70
- }
71
 
72
- $product = $order->get_product_from_item( $items[ $item_id ] );
73
- }
74
-
75
- if ( ! $product ) {
76
- return false;
77
- }
78
-
79
- return $product->needs_shipping();
80
  }
81
 
82
  /**
@@ -115,16 +94,16 @@ class WC_Shipstation_API_Shipnotify extends WC_Shipstation_API_Request {
115
  * Get Parsed XML response.
116
  *
117
  * @param string $xml XML.
118
- * @return string|bool
119
  */
120
  private function get_parsed_xml( $xml ) {
121
  if ( ! class_exists( 'WC_Safe_DOMDocument' ) ) {
122
- include_once( 'class-wc-safe-domdocument.php' );
123
  }
124
 
125
  libxml_use_internal_errors( true );
126
 
127
- $dom = new WC_Safe_DOMDocument;
128
  $success = $dom->loadXML( $xml );
129
 
130
  if ( ! $success ) {
@@ -217,7 +196,7 @@ class WC_Shipstation_API_Shipnotify extends WC_Shipstation_API_Request {
217
  }
218
 
219
  // Get real order ID from order object.
220
- $order_id = version_compare( WC_VERSION, '3.0.0', '<' ) ? $order->id : $order->get_id();
221
  if ( empty( $order_id ) ) {
222
  /* translators: 1: order id */
223
  $this->log( sprintf( __( 'Invalid order ID: %s', 'woocommerce-shipstation-integration' ), $order_id ) );
@@ -247,7 +226,7 @@ class WC_Shipstation_API_Shipnotify extends WC_Shipstation_API_Request {
247
  }
248
 
249
  $shipped_item_count += $qty_shipped;
250
- $shipped_items[] = $item_name . $item_sku . ' x ' . $qty_shipped;
251
  }
252
  }
253
  }
@@ -267,7 +246,7 @@ class WC_Shipstation_API_Shipnotify extends WC_Shipstation_API_Request {
267
  $tracking_number
268
  );
269
 
270
- $current_shipped_items = max( (int) get_post_meta( $order_id, '_shipstation_shipped_item_count', true ), 0 );
271
 
272
  if ( ( $current_shipped_items + $shipped_item_count ) >= $total_item_count ) {
273
  $order_shipped = true;
@@ -283,8 +262,8 @@ class WC_Shipstation_API_Shipnotify extends WC_Shipstation_API_Request {
283
  )
284
  );
285
 
286
- update_post_meta( $order_id, '_shipstation_shipped_item_count', $current_shipped_items + $shipped_item_count );
287
-
288
  } else {
289
  // If we don't have items from SS and order items in WC, or cannot parse
290
  // the XML, just complete the order as a whole.
@@ -308,9 +287,10 @@ class WC_Shipstation_API_Shipnotify extends WC_Shipstation_API_Request {
308
  wc_st_add_tracking_number( $order_id, $tracking_number, strtolower( $carrier ), $timestamp );
309
  } else {
310
  // You're using Shipment Tracking < 1.4.0. Please update!
311
- update_post_meta( $order_id, '_tracking_provider', strtolower( $carrier ) );
312
- update_post_meta( $order_id, '_tracking_number', $tracking_number );
313
- update_post_meta( $order_id, '_date_shipped', $timestamp );
 
314
  }
315
 
316
  $is_customer_note = 0;
@@ -329,12 +309,16 @@ class WC_Shipstation_API_Shipnotify extends WC_Shipstation_API_Request {
329
  }
330
 
331
  // Trigger action for other integrations.
332
- do_action( 'woocommerce_shipstation_shipnotify', $order, array(
333
- 'tracking_number' => $tracking_number,
334
- 'carrier' => $carrier,
335
- 'ship_date' => $timestamp,
336
- 'xml' => $shipstation_xml,
337
- ) );
 
 
 
 
338
 
339
  status_header( 200 );
340
  }
1
  <?php
2
 
3
  if ( ! defined( 'ABSPATH' ) ) {
4
+ exit; // Exit if accessed directly.
5
  }
6
 
7
  /**
30
 
31
  foreach ( $order->get_items() as $item_id => $item ) {
32
 
33
+ $product = is_callable( array( $item, 'get_product' ) ) ? $item->get_product() : false;
 
 
 
 
34
 
35
  if ( is_a( $product, 'WC_Product' ) && $product->needs_shipping() ) {
36
  $needs_shipping += ( $item['qty'] - abs( $order->get_qty_refunded_for_item( $item_id ) ) );
52
  * @return bool Returns true if item is shippable product.
53
  */
54
  private function is_shippable_item( $order, $item_id ) {
55
+ $item = $order->get_item( $item_id );
56
+ $product = is_callable( array( $item, 'get_product' ) ) ? $item->get_product() : false;
 
 
 
 
 
 
 
 
 
 
57
 
58
+ return $product ? $product->needs_shipping() : false;
 
 
 
 
 
 
 
59
  }
60
 
61
  /**
94
  * Get Parsed XML response.
95
  *
96
  * @param string $xml XML.
97
+ * @return SimpleXMLElement|false
98
  */
99
  private function get_parsed_xml( $xml ) {
100
  if ( ! class_exists( 'WC_Safe_DOMDocument' ) ) {
101
+ include_once 'class-wc-safe-domdocument.php';
102
  }
103
 
104
  libxml_use_internal_errors( true );
105
 
106
+ $dom = new WC_Safe_DOMDocument();
107
  $success = $dom->loadXML( $xml );
108
 
109
  if ( ! $success ) {
196
  }
197
 
198
  // Get real order ID from order object.
199
+ $order_id = $order->get_id();
200
  if ( empty( $order_id ) ) {
201
  /* translators: 1: order id */
202
  $this->log( sprintf( __( 'Invalid order ID: %s', 'woocommerce-shipstation-integration' ), $order_id ) );
226
  }
227
 
228
  $shipped_item_count += $qty_shipped;
229
+ $shipped_items[] = $item_name . $item_sku . ' x ' . $qty_shipped;
230
  }
231
  }
232
  }
246
  $tracking_number
247
  );
248
 
249
+ $current_shipped_items = max( (int) $order->get_meta( '_shipstation_shipped_item_count', true ), 0 );
250
 
251
  if ( ( $current_shipped_items + $shipped_item_count ) >= $total_item_count ) {
252
  $order_shipped = true;
262
  )
263
  );
264
 
265
+ $order->update_meta_data( '_shipstation_shipped_item_count', $current_shipped_items + $shipped_item_count );
266
+ $order->save();
267
  } else {
268
  // If we don't have items from SS and order items in WC, or cannot parse
269
  // the XML, just complete the order as a whole.
287
  wc_st_add_tracking_number( $order_id, $tracking_number, strtolower( $carrier ), $timestamp );
288
  } else {
289
  // You're using Shipment Tracking < 1.4.0. Please update!
290
+ $order->update_meta_data( '_tracking_provider', strtolower( $carrier ) );
291
+ $order->update_meta_data( '_tracking_number', $tracking_number );
292
+ $order->update_meta_data( '_date_shipped', $timestamp );
293
+ $order->save();
294
  }
295
 
296
  $is_customer_note = 0;
309
  }
310
 
311
  // Trigger action for other integrations.
312
+ do_action(
313
+ 'woocommerce_shipstation_shipnotify',
314
+ $order,
315
+ array(
316
+ 'tracking_number' => $tracking_number,
317
+ 'carrier' => $carrier,
318
+ 'ship_date' => $timestamp,
319
+ 'xml' => $shipstation_xml,
320
+ )
321
+ );
322
 
323
  status_header( 200 );
324
  }
includes/class-wc-shipstation-privacy.php CHANGED
@@ -22,7 +22,7 @@ class WC_ShipStation_Privacy extends WC_Abstract_Privacy {
22
  * @param string $email_address
23
  * @param int $page
24
  *
25
- * @return array WP_Post
26
  */
27
  protected function get_orders( $email_address, $page ) {
28
  $user = get_user_by( 'email', $email_address ); // Check if user has an ID in the DB to load stored personal data.
@@ -75,15 +75,15 @@ class WC_ShipStation_Privacy extends WC_Abstract_Privacy {
75
  'data' => array(
76
  array(
77
  'name' => __( 'ShipStation tracking provider', 'woocommerce-shipstation-integration' ),
78
- 'value' => get_post_meta( $order->get_id(), '_tracking_provider', true ),
79
  ),
80
  array(
81
  'name' => __( 'ShipStation tracking number', 'woocommerce-shipstation-integration' ),
82
- 'value' => get_post_meta( $order->get_id(), '_tracking_number', true ),
83
  ),
84
  array(
85
  'name' => __( 'ShipStation date shipped', 'woocommerce-shipstation-integration' ),
86
- 'value' => get_post_meta( $order->get_id(), '_date_shipped', true ) ? date( 'Y-m-d H:i:s', get_post_meta( $order->get_id(), '_date_shipped', true ) ) : '',
87
  ),
88
  ),
89
  );
@@ -140,23 +140,23 @@ class WC_ShipStation_Privacy extends WC_Abstract_Privacy {
140
  * @return array
141
  */
142
  protected function maybe_handle_order( $order ) {
143
- $order_id = $order->get_id();
144
- $item_count = get_post_meta( $order->get_id(), '_shipstation_shipped_item_count', true );
145
- $tracking_provider = get_post_meta( $order->get_id(), '_tracking_provider', true );
146
- $tracking_number = get_post_meta( $order->get_id(), '_tracking_number', true );
147
- $date_shipped = get_post_meta( $order->get_id(), '_date_shipped', true );
148
- $shipstation_exported = get_post_meta( $order->get_id(), '_shipstation_exported', true );
149
 
150
  if ( empty( $item_count ) && empty( $tracking_provider ) && empty( $tracking_number )
151
  && empty( $date_shipped ) && empty( $shipstation_exported ) ) {
152
  return array( false, false, array() );
153
  }
154
 
155
- delete_post_meta( $order->get_id(), '_shipstation_shipped_item_count' );
156
- delete_post_meta( $order->get_id(), '_tracking_provider' );
157
- delete_post_meta( $order->get_id(), '_tracking_number' );
158
- delete_post_meta( $order->get_id(), '_date_shipped' );
159
- delete_post_meta( $order->get_id(), '_shipstation_exported' );
 
160
 
161
  return array( true, false, array( __( 'ShipStation Order Data Erased.', 'woocommerce-shipstation-integration' ) ) );
162
  }
22
  * @param string $email_address
23
  * @param int $page
24
  *
25
+ * @return WC_Order[]
26
  */
27
  protected function get_orders( $email_address, $page ) {
28
  $user = get_user_by( 'email', $email_address ); // Check if user has an ID in the DB to load stored personal data.
75
  'data' => array(
76
  array(
77
  'name' => __( 'ShipStation tracking provider', 'woocommerce-shipstation-integration' ),
78
+ 'value' => $order->get_meta( '_tracking_provider', true ),
79
  ),
80
  array(
81
  'name' => __( 'ShipStation tracking number', 'woocommerce-shipstation-integration' ),
82
+ 'value' => $order->get_meta( '_tracking_number', true ),
83
  ),
84
  array(
85
  'name' => __( 'ShipStation date shipped', 'woocommerce-shipstation-integration' ),
86
+ 'value' => $order->get_meta( '_date_shipped', true ) ? date( 'Y-m-d H:i:s', $order->get_meta( '_date_shipped', true ) ) : '',
87
  ),
88
  ),
89
  );
140
  * @return array
141
  */
142
  protected function maybe_handle_order( $order ) {
143
+ $item_count = $order->get_meta( '_shipstation_shipped_item_count', true );
144
+ $tracking_provider = $order->get_meta( '_tracking_provider', true );
145
+ $tracking_number = $order->get_meta( '_tracking_number', true );
146
+ $date_shipped = $order->get_meta( '_date_shipped', true );
147
+ $shipstation_exported = $order->get_meta( '_shipstation_exported', true );
 
148
 
149
  if ( empty( $item_count ) && empty( $tracking_provider ) && empty( $tracking_number )
150
  && empty( $date_shipped ) && empty( $shipstation_exported ) ) {
151
  return array( false, false, array() );
152
  }
153
 
154
+ $order->delete_meta_data( '_shipstation_shipped_item_count' );
155
+ $order->delete_meta_data( '_tracking_provider' );
156
+ $order->delete_meta_data( '_tracking_number' );
157
+ $order->delete_meta_data( '_date_shipped' );
158
+ $order->delete_meta_data( '_shipstation_exported' );
159
+ $order->save();
160
 
161
  return array( true, false, array( __( 'ShipStation Order Data Erased.', 'woocommerce-shipstation-integration' ) ) );
162
  }
includes/trait-woocommerce-order-util.php ADDED
@@ -0,0 +1,131 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Class WooCommerce\OrderBarcodes\Order_Util file.
4
+ *
5
+ * @package WooCommerce\OrderBarcodes
6
+ */
7
+
8
+ namespace WooCommerce\ShipStation;
9
+
10
+ use Automattic\WooCommerce\Utilities\OrderUtil;
11
+
12
+ defined( 'ABSPATH' ) || exit;
13
+
14
+ /**
15
+ * Trait Order_Util
16
+ *
17
+ * A proxy-style trait that will help keep our code more stable and cleaner during the
18
+ * transition to WC Custom Order Tables.
19
+ */
20
+ trait Order_Util {
21
+ /**
22
+ * Constant variable for admin screen name.
23
+ *
24
+ * @var legacy_order_admin_screen.
25
+ */
26
+ public static $legacy_order_admin_screen = 'shop_order';
27
+
28
+ /**
29
+ * Checks whether the OrderUtil class exists
30
+ *
31
+ * @return bool
32
+ */
33
+ public static function wc_order_util_class_exists() {
34
+ return class_exists( 'Automattic\WooCommerce\Utilities\OrderUtil' );
35
+ }
36
+
37
+ /**
38
+ * Checks whether the OrderUtil class and the given method exist
39
+ *
40
+ * @param String $method_name Class method name.
41
+ *
42
+ * @return bool
43
+ */
44
+ public static function wc_order_util_method_exists( $method_name ) {
45
+ if ( ! self::wc_order_util_class_exists() ) {
46
+ return false;
47
+ }
48
+
49
+ if ( ! method_exists( 'Automattic\WooCommerce\Utilities\OrderUtil', $method_name ) ) {
50
+ return false;
51
+ }
52
+
53
+ return true;
54
+ }
55
+
56
+ /**
57
+ * Checks whether we are using custom order tables.
58
+ *
59
+ * @return bool
60
+ */
61
+ public static function custom_orders_table_usage_is_enabled() {
62
+ if ( ! self::wc_order_util_method_exists( 'custom_orders_table_usage_is_enabled' ) ) {
63
+ return false;
64
+ }
65
+
66
+ return OrderUtil::custom_orders_table_usage_is_enabled();
67
+ }
68
+
69
+ /**
70
+ * Returns the relevant order screen depending on whether
71
+ * custom order tables are being used.
72
+ *
73
+ * @return string
74
+ */
75
+ public static function get_order_admin_screen() {
76
+ if ( ! self::wc_order_util_method_exists( 'get_order_admin_screen' ) ) {
77
+ return self::$legacy_order_admin_screen;
78
+ }
79
+
80
+ return OrderUtil::get_order_admin_screen();
81
+ }
82
+
83
+ /**
84
+ * Check if the object is WP_Post object.
85
+ *
86
+ * @param Mixed $object Either Post object or Order object.
87
+ *
88
+ * @return Boolean
89
+ */
90
+ public static function is_wp_post( $object ) {
91
+ return is_a( $object, 'WP_Post' );
92
+ }
93
+
94
+ /**
95
+ * Check if the object is WC_Order object.
96
+ *
97
+ * @param Mixed $object Either Post object or Order object.
98
+ *
99
+ * @return Boolean
100
+ */
101
+ public static function is_wc_order( $object ) {
102
+ return is_a( $object, 'WC_Order' );
103
+ }
104
+
105
+ /**
106
+ * Check if the object is either WP_Post or WC_Order object.
107
+ *
108
+ * @param Mixed $object Either Post object or Order object.
109
+ *
110
+ * @return Boolean
111
+ */
112
+ public static function is_order_or_post( $object ) {
113
+ return self::is_wp_post( $object ) || self::is_wc_order( $object );
114
+ }
115
+
116
+ /**
117
+ * Returns the WC_Order object from the object passed to
118
+ * the add_meta_box callback function.
119
+ *
120
+ * @param WC_Order|WP_Post $post_or_order_object Either Post object or Order object.
121
+ *
122
+ * @return \WC_Order
123
+ */
124
+ public static function init_theorder_object( $post_or_order_object ) {
125
+ if ( ! self::wc_order_util_method_exists( 'init_theorder_object' ) ) {
126
+ return wc_get_order( $post_or_order_object->ID );
127
+ }
128
+
129
+ return OrderUtil::init_theorder_object( $post_or_order_object );
130
+ }
131
+ }
readme.txt CHANGED
@@ -2,9 +2,9 @@
2
  Contributors: woocommerce, automattic, royho, akeda, mattyza, bor0, woothemes, dwainm, laurendavissmith001
3
  Tags: shipping, woocommerce, automattic
4
  Requires at least: 4.4
5
- Tested up to: 5.8
6
  Requires PHP: 5.6
7
- Stable tag: 4.2.0
8
  License: GPLv3
9
  License URI: https://www.gnu.org/licenses/gpl-3.0.html
10
 
@@ -46,6 +46,9 @@ If you get stuck, you can ask for help in the Plugin Forum.
46
 
47
  == Changelog ==
48
 
 
 
 
49
  = 4.2.0 - 2022-09-07 =
50
  * Add - Filter for manipulating address export data.
51
  * Fix - Remove unnecessary files from plugin zip file.
2
  Contributors: woocommerce, automattic, royho, akeda, mattyza, bor0, woothemes, dwainm, laurendavissmith001
3
  Tags: shipping, woocommerce, automattic
4
  Requires at least: 4.4
5
+ Tested up to: 6.0
6
  Requires PHP: 5.6
7
+ Stable tag: 4.3.0
8
  License: GPLv3
9
  License URI: https://www.gnu.org/licenses/gpl-3.0.html
10
 
46
 
47
  == Changelog ==
48
 
49
+ = 4.3.0 - 2022-10-13 =
50
+ * Add - High-Performance Order Storage compatibility.
51
+
52
  = 4.2.0 - 2022-09-07 =
53
  * Add - Filter for manipulating address export data.
54
  * Fix - Remove unnecessary files from plugin zip file.
woocommerce-shipstation.php CHANGED
@@ -2,14 +2,14 @@
2
  /**
3
  * Plugin Name: WooCommerce - ShipStation Integration
4
  * Plugin URI: https://woocommerce.com/products/shipstation-integration/
5
- * Version: 4.2.0
6
  * Description: Adds ShipStation label printing support to WooCommerce. Requires server DomDocument support.
7
  * Author: WooCommerce
8
  * Author URI: https://woocommerce.com/
9
  * Text Domain: woocommerce-shipstation-integration
10
  * Domain Path: /languages
11
  * Tested up to: 6.0
12
- * WC tested up to: 6.8
13
  * WC requires at least: 3.4
14
  */
15
 
@@ -41,15 +41,17 @@ function woocommerce_shipstation_init() {
41
  return;
42
  }
43
 
44
- define( 'WC_SHIPSTATION_VERSION', '4.2.0' ); // WRCS: DEFINED_VERSION.
45
  define( 'WC_SHIPSTATION_FILE', __FILE__ );
46
 
47
  if ( ! defined( 'WC_SHIPSTATION_EXPORT_LIMIT' ) ) {
48
  define( 'WC_SHIPSTATION_EXPORT_LIMIT', 100 );
49
  }
50
 
51
- include_once( 'includes/class-wc-shipstation-integration.php' );
52
- include_once( 'includes/class-wc-shipstation-privacy.php' );
 
 
53
  }
54
 
55
  add_action( 'plugins_loaded', 'woocommerce_shipstation_init' );
2
  /**
3
  * Plugin Name: WooCommerce - ShipStation Integration
4
  * Plugin URI: https://woocommerce.com/products/shipstation-integration/
5
+ * Version: 4.3.0
6
  * Description: Adds ShipStation label printing support to WooCommerce. Requires server DomDocument support.
7
  * Author: WooCommerce
8
  * Author URI: https://woocommerce.com/
9
  * Text Domain: woocommerce-shipstation-integration
10
  * Domain Path: /languages
11
  * Tested up to: 6.0
12
+ * WC tested up to: 6.9
13
  * WC requires at least: 3.4
14
  */
15
 
41
  return;
42
  }
43
 
44
+ define( 'WC_SHIPSTATION_VERSION', '4.3.0' ); // WRCS: DEFINED_VERSION.
45
  define( 'WC_SHIPSTATION_FILE', __FILE__ );
46
 
47
  if ( ! defined( 'WC_SHIPSTATION_EXPORT_LIMIT' ) ) {
48
  define( 'WC_SHIPSTATION_EXPORT_LIMIT', 100 );
49
  }
50
 
51
+ // Include order util trait class file.
52
+ require_once 'includes/trait-woocommerce-order-util.php';
53
+ include_once 'includes/class-wc-shipstation-integration.php';
54
+ include_once 'includes/class-wc-shipstation-privacy.php';
55
  }
56
 
57
  add_action( 'plugins_loaded', 'woocommerce_shipstation_init' );