diff --git a/aftership-woocommerce-tracking.php b/aftership-woocommerce-tracking.php index 77513d6..760af14 100644 --- a/aftership-woocommerce-tracking.php +++ b/aftership-woocommerce-tracking.php @@ -3,7 +3,7 @@ * Plugin Name: AfterShip Tracking - All-In-One WooCommerce Order Tracking (Free plan available) * Plugin URI: http://aftership.com/ * Description: Track orders in one place. shipment tracking, automated notifications, order lookup, branded tracking page, delivery day prediction - * Version: 1.17.7 + * Version: 1.17.8 * Author: AfterShip * Author URI: http://aftership.com * @@ -20,7 +20,7 @@ require_once( 'woo-includes/woo-functions.php' ); -define( 'AFTERSHIP_VERSION', '1.17.7' ); +define( 'AFTERSHIP_VERSION', '1.17.8' ); define( 'AFTERSHIP_PATH', dirname( __FILE__ ) ); define( 'AFTERSHIP_ASSETS_URL', plugins_url() . '/' . basename( AFTERSHIP_PATH ) ); define( 'AFTERSHIP_SCRIPT_TAGS', 'aftership_script_tags' ); diff --git a/includes/class-aftership-actions.php b/includes/class-aftership-actions.php index 82667e9..6c9eb75 100644 --- a/includes/class-aftership-actions.php +++ b/includes/class-aftership-actions.php @@ -453,6 +453,8 @@ public function post_order_tracking( $order_id, $args ) { $tracking_item['slug'] = wc_clean( $args['slug'] ); $tracking_item['tracking_number'] = wc_clean( $args['tracking_number'] ); $tracking_item['tracking_id'] = md5( "{$tracking_item['slug']}-{$tracking_item['tracking_number']}" ); + // need apply default value + $tracking_item['additional_fields'] = array(); // line items for each tracking if ( isset( $args['line_items'] ) && is_array( $args['line_items'] ) && count( $args['line_items'] ) ) { $tracking_item['line_items'] = $args['line_items']; @@ -1103,7 +1105,7 @@ public function get_automizely_aftership_tracking_column( $order_id ) { ', - esc_html( isset( $provider_courier['name'] ) ? $provider_courier['name'] : '' ), + esc_html( isset( $provider_courier['name'] ) ? $provider_courier['name'] : $tracking_item['slug'] ), esc_url( $aftership_tracking_link ), esc_html( $tracking_item['tracking_number'] ), esc_html( $tracking_item['tracking_number'] ), diff --git a/includes/class-aftership-import-csv.php b/includes/class-aftership-import-csv.php index d93b89f..c314523 100644 --- a/includes/class-aftership-import-csv.php +++ b/includes/class-aftership-import-csv.php @@ -24,7 +24,7 @@ class AfterShip_Import_Csv { protected $selected_carrier_slugs; protected $actions; - public function __construct($actions, $couriers) { + public function __construct( $actions, $couriers ) { $this->actions = $actions; $this->options = get_option( 'aftership_option_name' ) ? get_option( 'aftership_option_name' ) : array(); $selected_carrier_slugs = explode( ',', ( isset( $this->options['couriers'] ) ? $this->options['couriers'] : '' ) ); @@ -108,6 +108,66 @@ public function add_menu() { 'import_csv_callback', ) ); + + // The user has enabled Import Tracking. + // Only need detect once: the user's store order number has used default id or has customized order number + if ( empty( $this->options['import_tracking'] ) ) { + // Query the user's latest order to determine: 1. whether the user has used a custom number 2. the custom fields used + $this->check_use_custom_order_number(); + } + } + + /** + * Query the user's latest order to determine: 1. whether the user has used a custom number 2. the custom fields used + */ + public function check_use_custom_order_number() { + // Query the user's latest order + $latest_orders = wc_get_orders( + array( + 'limit' => 1, + 'orderby' => 'date', + 'order' => 'DESC', + ) + ); + + if ( $latest_orders ) { + $use_custom_order_number = false; + $custom_order_number_key = ''; + + // Access the latest order details + $latest_order = $latest_orders[0]; + $latest_order_id = (string) $latest_order->get_id(); + $latest_order_number = $latest_order->get_order_number(); + + // Diff order id and order number + // 1. id = number , the user does not use a custom number + // 2. id != number , the user has used custom number + if ( $latest_order_id != $latest_order_number ) { + $use_custom_order_number = true; + + // Query the custom meta_data field which the user has used for value was order number value + $order_meta_data = $latest_order->get_meta_data(); + // filter object with a specific value (order number), get the custom order number key + $find_custom_fields = array_filter( + $order_meta_data, + function( $obj ) use ( $latest_order_number ) { + return $obj->value === $latest_order_number; + } + ); + if ( $find_custom_fields ) { + $custom_number_fields = array_values( $find_custom_fields ); + $custom_order_number_key = 'meta_data.' . $custom_number_fields[0]->key; + } + } + + // Write these two attribute to the settings API + $current_as_options = $this->options; + $current_as_options['import_tracking'] = array( + 'use_custom_order_number' => $use_custom_order_number, + 'custom_order_number_key' => $custom_order_number_key, + ); + update_option( 'aftership_option_name', $current_as_options ); + } } public function sanitize_text_field( $value ) { @@ -119,17 +179,12 @@ public function sanitize_text_field( $value ) { * * @return array */ - public function get_user_selected_couriers() { - if ( ! count( $this->selected_carrier_slugs ) ) { - return array(); - } - $user_selected_couriers = array(); + public function get_aftership_couriers() { + $aftership_couriers = array(); foreach ( $this->carriers as $carrier ) { - if ( in_array( $carrier['slug'], $this->selected_carrier_slugs, true ) ) { - $user_selected_couriers[] = array( $carrier['name'], $carrier['slug'] ); - } + $aftership_couriers[] = array( $carrier['name'], $carrier['slug'] ); } - return $user_selected_couriers; + return $aftership_couriers; } /** @@ -183,28 +238,38 @@ public function import_csv() { if ( ( $file_handle = fopen( $this->file_url, 'r' ) ) !== false ) { $header = fgetcsv( $file_handle, 0, ',' ); - $headers = array( + $headers = array( 'order_id' => esc_html__( 'Order ID', 'aftership-orders-tracking' ), + 'order_number' => esc_html__( 'Order Number', 'aftership-orders-tracking' ), 'tracking_number' => esc_html__( 'Tracking Number', 'aftership-orders-tracking' ), - 'carrier_slug' => esc_html__( 'Carrier Slug', 'aftership-orders-tracking' ), + 'carrier_slug' => esc_html__( 'Carrier Name', 'aftership-orders-tracking' ), ); - $index = array(); + $random_required_fields = array( + 'order_id', + 'order_number', + ); + $index = array(); + $random_required_fields_missing = 0; foreach ( $headers as $header_k => $header_v ) { $field_index = array_search( $map_to[ $header_k ], $header ); if ( $field_index === false ) { $index[ $header_k ] = - 1; + if ( in_array( $header_k, $random_required_fields ) ) { + $random_required_fields_missing ++; + } } else { $index[ $header_k ] = $field_index; } } $required_fields = array( 'order_id', + 'order_number', 'tracking_number', 'carrier_slug', ); foreach ( $required_fields as $required_field ) { - if ( 0 > $index[ $required_field ] ) { + if ( ( ! in_array( $required_field, $random_required_fields ) && 0 > $index[ $required_field ] ) || $random_required_fields_missing > 1 ) { wp_safe_redirect( add_query_arg( array( 'vi_at_error' => 1 ), admin_url( 'admin.php?page=aftership-orders-tracking-import-csv&step=mapping&file_url=' . urlencode( $this->file_url ) ) ) ); exit(); } @@ -270,13 +335,13 @@ public function import_csv() { exit(); } } elseif ( isset( $_POST['aftership_orders_tracking_download_carriers_file'] ) ) { - $filename = 'aftership-selected-carriers.csv'; + $filename = 'aftership-carriers.csv'; $header_row = array( esc_html__( 'Carrier Name', 'aftership-orders-tracking' ), esc_html__( 'Carrier Slug', 'aftership-orders-tracking' ), ); // Get user selected carriers - $data_rows = $this->get_user_selected_couriers(); + $data_rows = $this->get_aftership_couriers(); $fh = @fopen( 'php://output', 'w' ); fprintf( $fh, chr( 0xEF ) . chr( 0xBB ) . chr( 0xBF ) ); @@ -298,24 +363,28 @@ public function import_csv() { $filename = 'Import file example.csv'; $header_row = array( 'order_id' => esc_html__( 'Order ID', 'aftership-orders-tracking' ), + 'order_number' => esc_html__( 'Order Number', 'aftership-orders-tracking' ), 'tracking_number' => esc_html__( 'Tracking Number', 'aftership-orders-tracking' ), - 'carrier_slug' => esc_html__( 'Carrier Slug', 'aftership-orders-tracking' ), + 'carrier_slug' => esc_html__( 'Carrier Name', 'aftership-orders-tracking' ), ); $data_rows = array( array( + '111', '111', 'tracking_number1', - 'dhl-logistics', + 'DHL Express', ), array( + '112', '112', 'tracking_number2', - 'dhl-logistics', + 'DHL Express', ), array( + '113', '113', 'tracking_number3', - 'dhl-logistics', + 'DHL Express', ), ); $fh = @fopen( 'php://output', 'w' ); @@ -346,9 +415,60 @@ public function import_csv() { * * @throws Exception */ - public function import_tracking( $order_id, $data, $import_options ) { - if ( $order_id && count( $data ) ) { - $order_status = $import_options['order_status']; + public function import_tracking( $order_id = null, $data, $import_options, $order_number = null ) { + if ( ( $order_id || $order_number ) && count( $data ) ) { + $order_status = $import_options['order_status']; + $original_order_id = $order_id; + + /** + * New feature: support csv import tracking by order number + */ + // Need distinguish number query order,find order id when Order ID missing + if ( empty( $order_id ) && ! empty( $order_number ) ) { + // 1. The customer store has used custom order number + // Check AfterShip settings - import_tracking + $as_import_tracking_setting = $this->options['import_tracking'] ? $this->options['import_tracking'] : null; + if ( $as_import_tracking_setting && $as_import_tracking_setting['use_custom_order_number'] === true ) { + // Parse the custom field, eg: "meta_data._order_number" + $field_name_define = explode( '.', $as_import_tracking_setting['custom_order_number_key'] ); + // Need to distinguish number query order,find order id when Order ID missing + // remove first char (#) from number + $order_number = substr( $order_number, 0, 1 ) === '#' ? substr( $order_number, 1 ) : $order_number; + // try to get order id by order number + $query_custom_number_args = array( + 'limit' => 1, + 'post_type' => 'shop_order', + 'post_status' => 'any', + ); + // Define query schema for number (Can be expanded later, even if the user is not defined under meta_data) + if ( $field_name_define[0] == 'meta_data' ) { + $query_custom_number_args['meta_query'] = array( + array( + 'key' => $field_name_define[1], + 'value' => $order_number, // here you pass the Order Number + 'compare' => '=', + ), + ); + } + if ( count( $query_custom_number_args ) == 3 ) { + // IF query field not found, logger + AFTERSHIP_ORDERS_TRACKING_IMPORT_LOG::log( esc_html__( "Skipped, Can't find custom order number field by number {$order_number}", 'aftership-orders-tracking' ) ); + return; + } + + $order_record = new WP_Query( $query_custom_number_args ); + if ( ! empty( $order_record->posts ) ) { + $order_id = $order_record->posts[0]->ID; + } else { + // IF order not found, logger + AFTERSHIP_ORDERS_TRACKING_IMPORT_LOG::log( esc_html__( "Skipped, Can't be found for order by number {$order_number}", 'aftership-orders-tracking' ) ); + return; + } + } else { + // 2. Default order number from order id + $order_id = $order_number; + } + } $order = wc_get_order( $order_id ); if ( $order ) { @@ -392,11 +512,11 @@ public function import_tracking( $order_id, $data, $import_options ) { } } - AFTERSHIP_ORDERS_TRACKING_IMPORT_LOG::log( esc_html__( "Import tracking successfully for order {$order_id}", 'aftership-orders-tracking' ) ); + AFTERSHIP_ORDERS_TRACKING_IMPORT_LOG::log( esc_html__( "Import tracking successfully for order: order id ({$original_order_id}), order number ({$order_number})", 'aftership-orders-tracking' ) ); } } else { // Skip - The store can't find this order - AFTERSHIP_ORDERS_TRACKING_IMPORT_LOG::log( esc_html__( "Skipped, Can't be found for order {$order_id}", 'aftership-orders-tracking' ) ); + AFTERSHIP_ORDERS_TRACKING_IMPORT_LOG::log( esc_html__( "Skipped, Can't find order: order id ({$original_order_id}), order number ({$order_number})", 'aftership-orders-tracking' ) ); } } } @@ -507,8 +627,10 @@ public function import_order_tracking() { 'order_status' => $order_status, ); $orders = array(); + $order_numbers = array(); $order_data = array(); $order_id = ''; + $order_number = ''; $ftell_2 = 0; if ( $ftell > 0 ) { fseek( $file_handle, $ftell ); @@ -520,33 +642,37 @@ public function import_order_tracking() { } while ( ( $item = fgetcsv( $file_handle, 0, ',' ) ) !== false ) { $count ++; - $order_id_1 = $item[ $index['order_id'] ]; + $order_id_1 = $index['order_id'] > -1 ? $item[ $index['order_id'] ] : ''; + $order_number_1 = $index['order_number'] > -1 ? $item[ $index['order_number'] ] : ''; $tracking_number = $item[ $index['tracking_number'] ]; $carrier_slug = $item[ $index['carrier_slug'] ]; $start ++; $ftell_1 = ftell( $file_handle ); // Check if has value for required fields - if ( empty( $order_id_1 ) || empty( $carrier_slug ) || empty( $tracking_number ) ) { + // number or id at least one required + if ( ( empty( $order_id_1 ) && empty( $order_number_1 ) ) || empty( $tracking_number ) || empty( $carrier_slug ) ) { $ftell_2 = $ftell_1; // If exist empty, skip - AFTERSHIP_ORDERS_TRACKING_IMPORT_LOG::log( esc_html__( "Skipped, missing value of required fields for order {$order_id_1}", 'aftership-orders-tracking' ) ); - continue; - } - // Check if valid carrier slug - if ( ! in_array( $carrier_slug, $this->selected_carrier_slugs, true ) ) { - // invalid slug, skip - AFTERSHIP_ORDERS_TRACKING_IMPORT_LOG::log( esc_html__( "Skipped, invalid carrier slug for order {$order_id_1}, slug: {$carrier_slug}", 'aftership-orders-tracking' ) ); + AFTERSHIP_ORDERS_TRACKING_IMPORT_LOG::log( esc_html__( "Skipped, missing value of required fields for order id {$order_id_1}, order number {$order_number_1}", 'aftership-orders-tracking' ) ); continue; } + // If not empty, Check if valid carrier slug + // if ( ! empty($carrier_slug) && ! in_array( $carrier_slug, $this->selected_carrier_slugs, true ) ) { + // invalid slug, skip + // AFTERSHIP_ORDERS_TRACKING_IMPORT_LOG::log( esc_html__( "Skipped, invalid carrier slug for order {$order_id_1}, slug: {$carrier_slug}", 'aftership-orders-tracking' ) ); + // continue; + // } // set time limit vi_at_set_time_limit(); - if ( ! in_array( $order_id_1, $orders ) ) { + if ( ! in_array( $order_id_1, $orders ) || ! in_array( $order_number_1, $order_numbers ) ) { /*create previous order*/ - $this->import_tracking( $order_id, $order_data, $import_options ); + $this->import_tracking( $order_id, $order_data, $import_options, $order_number ); if ( count( $orders ) < $orders_per_request ) { - $order_id = $order_id_1; - $orders[] = $order_id; - $order_data = array( + $order_id = $order_id_1; + $order_number = $order_number_1; + $orders[] = $order_id; + $order_numbers[] = $order_number; + $order_data = array( array( 'tracking_number' => $tracking_number, 'carrier_slug' => $carrier_slug, @@ -577,7 +703,7 @@ public function import_order_tracking() { $next_item = fgetcsv( $file_handle, 0, ',' ); if ( false === $next_item ) { /*create previous order*/ - $this->import_tracking( $order_id, $order_data, $import_options ); + $this->import_tracking( $order_id, $order_data, $import_options, $order_number ); fclose( $file_handle ); AFTERSHIP_ORDERS_TRACKING_IMPORT_LOG::log( esc_html__( 'Finish importing tracking', 'aftership-orders-tracking' ) ); @@ -592,22 +718,25 @@ public function import_order_tracking() { ); } else { $count ++; - $order_id_2 = $next_item[ $index['order_id'] ]; + $order_id_2 = $index['order_id'] > -1 ? $next_item[ $index['order_id'] ] : ''; + $order_number_2 = $index['order_number'] > -1 ? $next_item[ $index['order_number'] ] : ''; $tracking_number = $next_item[ $index['tracking_number'] ]; $carrier_slug = $next_item[ $index['carrier_slug'] ]; $start ++; $ftell_2 = ftell( $file_handle ); - if ( empty( $order_id_2 ) || empty( $carrier_slug ) || empty( $tracking_number ) ) { + if ( ( empty( $order_id_2 ) && empty( $order_number_2 ) ) || empty( $tracking_number ) || empty( $carrier_slug ) ) { continue; } - if ( ! in_array( $order_id_2, $orders ) ) { + if ( ! in_array( $order_id_2, $orders ) || ! in_array( $order_number_2, $order_numbers ) ) { /*create previous order*/ - $this->import_tracking( $order_id, $order_data, $import_options ); + $this->import_tracking( $order_id, $order_data, $import_options, $order_number ); if ( count( $orders ) < $orders_per_request ) { - $order_id = $order_id_2; - $orders[] = $order_id; - $order_data = array( + $order_id = $order_id_2; + $orders[] = $order_id; + $order_number = $order_number_2; + $order_numbers[] = $order_number; + $order_data = array( array( 'tracking_number' => $tracking_number, 'carrier_slug' => $carrier_slug, @@ -636,7 +765,7 @@ public function import_order_tracking() { unset( $next_item ); } } - $this->import_tracking( $order_id, $order_data, $import_options ); + $this->import_tracking( $order_id, $order_data, $import_options, $order_number ); fclose( $file_handle ); AFTERSHIP_ORDERS_TRACKING_IMPORT_LOG::log( esc_html__( 'Finish importing tracking', 'aftership-orders-tracking' ) ); @@ -707,8 +836,9 @@ public function admin_enqueue_scripts() { 'order_status' => isset( $_POST['aftership_orders_tracking_order_status'] ) ? sanitize_text_field( $_POST['aftership_orders_tracking_order_status'] ) : '', 'required_fields' => array( 'order_id' => esc_html__( 'Order ID', 'aftership-orders-tracking' ), + 'order_number' => esc_html__( 'Order Number', 'aftership-orders-tracking' ), 'tracking_number' => esc_html__( 'Tracking Number', 'aftership-orders-tracking' ), - 'carrier_slug' => esc_html__( 'Carrier Slug', 'aftership-orders-tracking' ), + 'carrier_slug' => esc_html__( 'Carrier Name', 'aftership-orders-tracking' ), ), ) ); @@ -769,7 +899,7 @@ public function import_csv_callback() { esc_html__( 'Order ID', 'aftership-orders-tracking' ), + 'order_number' => esc_html__( 'Order Number', 'aftership-orders-tracking' ), 'tracking_number' => esc_html__( 'Tracking Number', 'aftership-orders-tracking' ), - 'carrier_slug' => esc_html__( 'Carrier Slug', 'aftership-orders-tracking' ), + 'carrier_slug' => esc_html__( 'Carrier Name', 'aftership-orders-tracking' ), ); $description = array( 'order_id' => '', + 'order_number' => '', 'tracking_number' => '', 'carrier_slug' => '', ); @@ -880,9 +1013,10 @@ class="vi-ui fluid dropdown"> ?> - + esc_html__( 'Order Number', 'aftership-orders-tracking' ), + 'order_number' => esc_html__( 'Order ID', 'aftership-orders-tracking' ), + ); if ( in_array( $header_k, $required_fields ) ) { - $label .= '(*Required)'; + if ( in_array( $header_k, array_keys( $random_required_fields ) ) ) { + $label .= '(*Required when missing ' . $random_required_fields[ $header_k ] . ')'; + } else { + $label .= '(*Required)'; + } } ?> @@ -955,24 +1098,21 @@ class="button" ?>
diff --git a/readme.txt b/readme.txt index 639aa29..33d19a7 100644 --- a/readme.txt +++ b/readme.txt @@ -4,7 +4,7 @@ Donate link: https://www.aftership.com/ Tags: woocommerce shipping,woocommerce tracking,shipment tracking,order tracking, woocommerce,track order,dhl,ups,usps,fedex,shipping,tracking,order Requires at least: 2.9 Tested up to: 6.3 -Stable tag: 1.17.7 +Stable tag: 1.17.8 License: GPLv2 or later License URI: http://www.gnu.org/licenses/gpl-2.0.html @@ -141,6 +141,9 @@ Tailor a dynamic branded tracking page. Upload promotional banner, logo, and fav == Changelog == += 1.17.8 = +* Enhancement: support order number column (csv template) for Import Tracking + = 1.17.0 = * Enhancement: support script tags API