<?php
/**
* WooCommerceShipmentTracking integration file.
*
* @package Automattic\WCShipping\Integrations
*/
namespace Automattic\WCShipping\Integrations;
use Automattic\WCShipping\Utils;
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/**
* Class WooCommerceShipmentTracking
*
* @package Automattic\WCShipping\Integrations
*/
class WooCommerceShipmentTracking {
/**
* Constructor.
*/
public static function init() {
add_filter( 'woocommerce_order_get__wc_shipment_tracking_items', array( __CLASS__, 'modify_tracking_data_stored_erenously' ), 10, 2 );
}
/**
* Add a WooCommerce Shipment Tracking compatible tracking number to an order.
* We will use the WC Shipment Tracking functions if the plugin is installed
* otherwise we will use our own custom implementation so data is present for
* when the plugin is installed, but in the same format.
*
* @param int $order_id Order ID.
* @param string $tracking_number Tracking number.
* @param string $carrier Carrier ID.
* @param string $service Service Name.
*
* @return void
*/
public static function add_tracking_number_to_order( $order_id, $tracking_number, $carrier, $service = '' ) {
// Workaround for the UPS DAP carrier ID which is not supported by WC Shipment Tracking.
if ( 'upsdap' === $carrier ) {
$carrier = 'ups';
}
// To avoid conflicts with the WC Shipment Tracking carriers/providers and to make life easier we will use custom defined ones.
$tracking_url = Utils::get_tracking_url( $carrier, $tracking_number );
if ( self::is_st_installed() ) {
self::add_tracking_using_st_installed_functions( $order_id, $tracking_number, $carrier, $tracking_url );
return;
}
// If we made it till here then the WC Shipment Tracking plugin is not installed and we will use our own custom implementation.
$order = \wc_get_order( $order_id );
if ( ! $order instanceof \WC_Order ) {
return;
}
$tracking_item = array(
'tracking_provider' => '',
'custom_tracking_provider' => \wc_clean( $service ? $service : $carrier ),
'tracking_number' => \wc_clean( $tracking_number ),
'custom_tracking_link' => \wc_clean( $tracking_url ),
);
// Generate a unique key for the tracking item.
$key = md5( "{$tracking_item['custom_tracking_provider']}-{$tracking_item['tracking_number']}" . microtime() );
$tracking_item['tracking_id'] = $key;
$tracking_items = self::get_st_tracking_items( $order_id );
$tracking_items[] = $tracking_item;
/**
* Filter the tracking items before adding it into order meta.
* We will use the same filter used in WC Shipment Tracking to keep integrations working.
*
* @param array $tracking_items List of tracking item.
* @param array $tracking_item New tracking item.
* @param int $order_id Order ID.
*
* @since 1.0.0
*/
$tracking_items = apply_filters( 'wcshipping_tracking_before_add_tracking_items', $tracking_items, $tracking_item, $order_id );
self::save_st_tracking_items( $order_id, $tracking_items );
}
/**
* Save the tracking items to the order using the WC Shipment Tracking format.
*
* @param int $order_id Order ID.
* @param array $tracking_items Tracking items.
*
* @return void
*/
public static function save_st_tracking_items( $order_id, $tracking_items ) {
$order = \wc_get_order( $order_id );
if ( ! $order instanceof \WC_Order ) {
return;
}
// Always re-index the array.
$tracking_items = array_values( $tracking_items );
$order->update_meta_data( '_wc_shipment_tracking_items', $tracking_items );
$order->save();
}
/**
* Gets all tracking items from the post meta array for an order.
*
* @param int $order_id Order ID.
*
* @return array Tracking items
*/
public static function get_st_tracking_items( $order_id ) {
$order = \wc_get_order( $order_id );
if ( ! $order instanceof \WC_Order ) {
return array();
}
$tracking_items = $order->get_meta( '_wc_shipment_tracking_items' );
if ( is_array( $tracking_items ) ) {
return $tracking_items;
} else {
return array();
}
}
/**
* Check if WooCommerce Shipment Tracking is installed.
*
* @return bool
*/
public static function is_st_installed() {
return class_exists( 'WC_Shipment_Tracking' ) && function_exists( 'wc_st_add_tracking_number' );
}
/**
* Add tracking number using WC Shipment Tracking function, if the plugin is installed.
*
* @param int $order_id Order ID.
* @param string $tracking_number Tracking number.
* @param string $carrier Carrier ID.
* @param string $tracking_url Custom Tracking URL.
*
* @return void
*/
public static function add_tracking_using_st_installed_functions( $order_id, $tracking_number, $carrier, $tracking_url ) {
if ( ! self::is_st_installed() ) {
return;
}
\wc_st_add_tracking_number( $order_id, $tracking_number, $carrier, null, $tracking_url );
}
/**
* Modify tracking data stored erroneously due to previous a bug.
*
* @param mixed $value The value of the meta key.
* @param WC_Order $order The order object.
*
* @return mixed The modified value.
*/
public static function modify_tracking_data_stored_erenously( $value, $order ) {
// Only if a shipping label is present on the order.
$labels = $order->get_meta( 'wcshipping_labels', true );
if ( ! $labels ) {
return $value;
}
if ( ! is_array( $value ) ) {
return $value;
}
// Check if the value is missing the custom tracking link and add it.
foreach ( $value as $index => &$tracking_item ) {
// Only items with the same custom tracking link and tracking number will be updated.
if ( $tracking_item['custom_tracking_link'] !== $tracking_item['tracking_number'] ) {
continue;
}
// Pick label from array of arrays checking the `tracking` key against `tracking_number`.
$label = array_values(
array_filter(
$labels,
function ( $label ) use ( $tracking_item ) {
return $label['tracking'] === $tracking_item['tracking_number'];
}
)
)[0];
if ( ! $label ) {
continue;
}
// If we get to this point then we have a label, lets update the url.
$tracking_item['custom_tracking_link'] = Utils::get_tracking_url( $label['carrier_id'], $label['tracking'] );
}
return $value;
}
}