Version Description
- Support Multiple Tracking Number
Download this release
Release Info
Developer | aftership |
Plugin | AfterShip – WooCommerce Tracking |
Version | 1.11.0 |
Comparing to | |
See all releases |
Code changes from version 1.10.5 to 1.11.0
- .huskyrc +5 -0
- aftership-backward-compatibility.php +0 -21
- aftership-fields.php +0 -86
- aftership-functions.php +0 -15
- aftership-woocommerce-tracking.php +230 -0
- aftership.php +16 -608
- api/class-aftership-api-authentication.php +0 -129
- api/class-aftership-api-orders.php +0 -575
- api/class-aftership-api-resource.php +0 -416
- api/class-aftership-api-server.php +0 -1031
- api/class-aftership-api-v3-orders.php +0 -424
- assets/css/admin.css +117 -6
- assets/js/admin.js +0 -123
- assets/js/couriers.js +0 -1
- assets/js/couriers.json +4718 -0
- assets/js/index.js +12 -0
- assets/js/meta-box.js +279 -0
- assets/js/setting.js +0 -42
- class-aftership-api.php +0 -188
- class-aftership-dependencies.php +0 -35
- class-aftership-settings.php +0 -295
- composer.json +8 -0
- composer.lock +1991 -0
- includes/api/class-aftership-api-authentication.php +124 -0
- {api → includes/api}/class-aftership-api-common-json-handler.php +0 -0
- {api → includes/api}/class-aftership-api-json-handler.php +0 -0
- includes/api/class-aftership-api-orders.php +573 -0
- includes/api/class-aftership-api-resource.php +444 -0
- includes/api/class-aftership-api-server.php +1041 -0
- includes/api/class-aftership-api.php +191 -0
- {api → includes/api}/interface-aftership-api-handler.php +7 -5
- includes/api/v3/class-aftership-api-orders.php +421 -0
- includes/api/v4/class-aftership-api-orders.php +441 -0
- includes/api/v4/class-aftership-api-settings.php +80 -0
- includes/class-aftership-actions.php +833 -0
- includes/class-aftership-settings.php +187 -0
- phpcs.xml +21 -0
- readme.txt +3 -4
- templates/email/plain/tracking-info.php +30 -0
- templates/email/tracking-info.php +44 -0
- templates/myaccount/view-order.php +54 -0
- woo-includes/class-wc-dependencies.php +28 -0
- woo-includes/woo-functions.php +295 -0
.huskyrc
ADDED
@@ -0,0 +1,5 @@
|
|
|
|
|
|
|
|
|
|
|
1 |
+
{
|
2 |
+
"hooks": {
|
3 |
+
"pre-commit": "./vendor/bin/phpcbf ./"
|
4 |
+
}
|
5 |
+
}
|
aftership-backward-compatibility.php
DELETED
@@ -1,21 +0,0 @@
|
|
1 |
-
<?php
|
2 |
-
/**
|
3 |
-
* Get woo order ID
|
4 |
-
*/
|
5 |
-
if ( ! function_exists( 'get_order_id' ) ) {
|
6 |
-
function get_order_id($order) {
|
7 |
-
return (method_exists($order, 'get_id'))? $order->get_id() : $order->id;
|
8 |
-
}
|
9 |
-
}
|
10 |
-
|
11 |
-
/**
|
12 |
-
* @see https://docs.woocommerce.com/wc-apidocs/source-class-WC_Abstract_Legacy_Order.html#406
|
13 |
-
* Get attribute from WC_Order
|
14 |
-
*
|
15 |
-
*/
|
16 |
-
if ( ! function_exists( 'order_post_meta_getter' ) ) {
|
17 |
-
function order_post_meta_getter($order, $attr) {
|
18 |
-
$meta = get_post_meta(get_order_id($order), '_'. $attr, true);
|
19 |
-
return $meta;
|
20 |
-
}
|
21 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
aftership-fields.php
DELETED
@@ -1,86 +0,0 @@
|
|
1 |
-
<?php
|
2 |
-
/**
|
3 |
-
* Created by PhpStorm.
|
4 |
-
* User: Sunny Chow
|
5 |
-
* Date: 4/2/15
|
6 |
-
* Time: 6:08 PM
|
7 |
-
*/
|
8 |
-
|
9 |
-
$aftership_fields = array(
|
10 |
-
'aftership_tracking_provider_name' => array(
|
11 |
-
'id' => 'aftership_tracking_provider_name',
|
12 |
-
'type' => 'text',
|
13 |
-
'label' => '',
|
14 |
-
'placeholder' => '',
|
15 |
-
'description' => '',
|
16 |
-
'class' => 'hidden'
|
17 |
-
),
|
18 |
-
|
19 |
-
'aftership_tracking_required_fields' => array(
|
20 |
-
'id' => 'aftership_tracking_required_fields',
|
21 |
-
'type' => 'text',
|
22 |
-
'label' => '',
|
23 |
-
'placeholder' => '',
|
24 |
-
'description' => '',
|
25 |
-
'class' => 'hidden'
|
26 |
-
),
|
27 |
-
|
28 |
-
'aftership_tracking_number' => array(
|
29 |
-
'id' => 'aftership_tracking_number',
|
30 |
-
'type' => 'text',
|
31 |
-
'label' => 'Tracking number',
|
32 |
-
'placeholder' => '',
|
33 |
-
'description' => '',
|
34 |
-
'class' => ''
|
35 |
-
),
|
36 |
-
|
37 |
-
'aftership_tracking_shipdate' => array(
|
38 |
-
'key' => 'tracking_ship_date',
|
39 |
-
'id' => 'aftership_tracking_shipdate',
|
40 |
-
'type' => 'date',
|
41 |
-
'label' => 'Date shipped',
|
42 |
-
'placeholder' => 'YYYY-MM-DD',
|
43 |
-
'description' => '',
|
44 |
-
'class' => 'date-picker-field hidden-field'
|
45 |
-
),
|
46 |
-
|
47 |
-
'aftership_tracking_postal' => array(
|
48 |
-
'key' => 'tracking_postal_code',
|
49 |
-
'id' => 'aftership_tracking_postal',
|
50 |
-
'type' => 'text',
|
51 |
-
'label' => 'Postal Code',
|
52 |
-
'placeholder' => '',
|
53 |
-
'description' => '',
|
54 |
-
'class' => 'hidden-field'
|
55 |
-
),
|
56 |
-
|
57 |
-
'aftership_tracking_account' => array(
|
58 |
-
'key' => 'tracking_account_number',
|
59 |
-
'id' => 'aftership_tracking_account',
|
60 |
-
'type' => 'text',
|
61 |
-
'label' => 'Account name',
|
62 |
-
'placeholder' => '',
|
63 |
-
'description' => '',
|
64 |
-
'class' => 'hidden-field'
|
65 |
-
),
|
66 |
-
|
67 |
-
'aftership_tracking_key' => array(
|
68 |
-
'key' => 'tracking_key',
|
69 |
-
'id' => 'aftership_tracking_key',
|
70 |
-
'type' => 'text',
|
71 |
-
'label' => 'Tracking key',
|
72 |
-
'placeholder' => '',
|
73 |
-
'description' => '',
|
74 |
-
'class' => 'hidden-field'
|
75 |
-
),
|
76 |
-
|
77 |
-
'aftership_tracking_destination_country' => array(
|
78 |
-
'key' => 'tracking_destination_country',
|
79 |
-
'id' => 'aftership_tracking_destination_country',
|
80 |
-
'type' => 'text',
|
81 |
-
'label' => 'Destination Country',
|
82 |
-
'placeholder' => '',
|
83 |
-
'description' => '',
|
84 |
-
'class' => 'hidden-field'
|
85 |
-
)
|
86 |
-
);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
aftership-functions.php
DELETED
@@ -1,15 +0,0 @@
|
|
1 |
-
<?php
|
2 |
-
/**
|
3 |
-
* Functions used by plugins
|
4 |
-
*/
|
5 |
-
if ( ! class_exists( 'AfterShip_Dependencies' ) )
|
6 |
-
require_once 'class-aftership-dependencies.php';
|
7 |
-
|
8 |
-
/**
|
9 |
-
* WC Detection
|
10 |
-
*/
|
11 |
-
if ( ! function_exists( 'is_woocommerce_active' ) ) {
|
12 |
-
function is_woocommerce_active() {
|
13 |
-
return AfterShip_Dependencies::woocommerce_active_check();
|
14 |
-
}
|
15 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
aftership-woocommerce-tracking.php
ADDED
@@ -0,0 +1,230 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/*
|
3 |
+
Plugin Name: Ecommerce Order Tracking and Shipment Notifications - AfterShip
|
4 |
+
Plugin URI: http://aftership.com/
|
5 |
+
Description: Effortless order tracking synced from all shipping providers for your ecommerce customers. Include a branded tracking page and automated delivery notifications.
|
6 |
+
Version: 1.11.0
|
7 |
+
Author: AfterShip
|
8 |
+
Author URI: http://aftership.com
|
9 |
+
|
10 |
+
Copyright: © AfterShip
|
11 |
+
*/
|
12 |
+
|
13 |
+
if ( ! defined( 'ABSPATH' ) ) {
|
14 |
+
exit;
|
15 |
+
}
|
16 |
+
|
17 |
+
/**
|
18 |
+
* Required functions
|
19 |
+
*/
|
20 |
+
|
21 |
+
require_once( 'woo-includes/woo-functions.php' );
|
22 |
+
|
23 |
+
define( 'AFTERSHIP_VERSION', '1.11.0' );
|
24 |
+
|
25 |
+
if ( is_woocommerce_active() ) {
|
26 |
+
|
27 |
+
/**
|
28 |
+
* AfterShip class
|
29 |
+
*/
|
30 |
+
if ( ! class_exists( 'AfterShip' ) ) {
|
31 |
+
|
32 |
+
/**
|
33 |
+
* Plugin's main class.
|
34 |
+
*/
|
35 |
+
class AfterShip {
|
36 |
+
|
37 |
+
|
38 |
+
/**
|
39 |
+
* Instance of AfterShip_Actions.
|
40 |
+
*
|
41 |
+
* @var AfterShip_Actions
|
42 |
+
*/
|
43 |
+
public $actions;
|
44 |
+
|
45 |
+
/**
|
46 |
+
* Instance of AfterShip_API.
|
47 |
+
*
|
48 |
+
* @var AfterShip_API
|
49 |
+
*/
|
50 |
+
public $api;
|
51 |
+
|
52 |
+
/**
|
53 |
+
* Plugin file.
|
54 |
+
*
|
55 |
+
* @var string
|
56 |
+
*/
|
57 |
+
public $plugin_file;
|
58 |
+
|
59 |
+
/**
|
60 |
+
* Plugin dir.
|
61 |
+
*
|
62 |
+
* @var string
|
63 |
+
*/
|
64 |
+
public $plugin_dir;
|
65 |
+
|
66 |
+
/**
|
67 |
+
* Plugin URL.
|
68 |
+
*
|
69 |
+
* @var string
|
70 |
+
*/
|
71 |
+
public $plugin_url;
|
72 |
+
|
73 |
+
|
74 |
+
/**
|
75 |
+
* Setting options
|
76 |
+
*
|
77 |
+
* @var array
|
78 |
+
*/
|
79 |
+
public $options = array();
|
80 |
+
|
81 |
+
|
82 |
+
/**
|
83 |
+
* Couriers
|
84 |
+
*
|
85 |
+
* @var array
|
86 |
+
*/
|
87 |
+
public $couriers = array();
|
88 |
+
|
89 |
+
/**
|
90 |
+
* Can change it on setting page
|
91 |
+
*
|
92 |
+
* @var bool
|
93 |
+
*/
|
94 |
+
public $use_track_button = false;
|
95 |
+
|
96 |
+
|
97 |
+
/**
|
98 |
+
* Can change it on setting page
|
99 |
+
*
|
100 |
+
* @var bool
|
101 |
+
*/
|
102 |
+
public $custom_domain = 'track.aftership.com';
|
103 |
+
|
104 |
+
|
105 |
+
/**
|
106 |
+
* Selected couriers
|
107 |
+
*
|
108 |
+
* @var array
|
109 |
+
*/
|
110 |
+
public $selected_couriers = array();
|
111 |
+
|
112 |
+
/**
|
113 |
+
* Constructor
|
114 |
+
*/
|
115 |
+
public function __construct() {
|
116 |
+
$this->plugin_file = __FILE__;
|
117 |
+
$this->plugin_dir = untrailingslashit( plugin_dir_path( __FILE__ ) );
|
118 |
+
$this->plugin_url = untrailingslashit( plugin_dir_url( __FILE__ ) );
|
119 |
+
|
120 |
+
$this->options = get_option( 'aftership_option_name' );
|
121 |
+
$this->couriers = json_decode( file_get_contents( $this->plugin_dir . '/assets/js/couriers.json' ), true );
|
122 |
+
$this->selected_couriers = $this->get_selected_couriers();
|
123 |
+
$this->use_track_button = isset( $this->options['use_track_button'] ) ? $this->options['use_track_button'] : $this->use_track_button;
|
124 |
+
$this->custom_domain = isset( $this->options['custom_domain'] ) ? $this->options['custom_domain'] : $this->custom_domain;
|
125 |
+
|
126 |
+
// Include required files.
|
127 |
+
$this->includes();
|
128 |
+
|
129 |
+
add_action( 'admin_print_styles', array( $this->actions, 'admin_styles' ) );
|
130 |
+
add_action( 'add_meta_boxes', array( $this->actions, 'add_meta_box' ) );
|
131 |
+
add_action( 'woocommerce_process_shop_order_meta', array( $this->actions, 'save_meta_box' ), 0, 2 );
|
132 |
+
add_action( 'plugins_loaded', array( $this->actions, 'load_plugin_textdomain' ) );
|
133 |
+
|
134 |
+
// View Order Page.
|
135 |
+
add_action( 'woocommerce_view_order', array( $this->actions, 'display_tracking_info' ) );
|
136 |
+
add_action( 'woocommerce_email_before_order_table', array( $this->actions, 'email_display' ), 0, 4 );
|
137 |
+
|
138 |
+
// Order page metabox actions.
|
139 |
+
add_action( 'wp_ajax_aftership_get_item', array( $this->actions, 'get_meta_box_item_ajax' ) );
|
140 |
+
add_action( 'wp_ajax_aftership_delete_item', array( $this->actions, 'meta_box_delete_tracking' ) );
|
141 |
+
add_action( 'wp_ajax_aftership_save_form', array( $this->actions, 'save_meta_box_ajax' ) );
|
142 |
+
add_action( 'wp_ajax_aftership_get_items', array( $this->actions, 'get_meta_box_items_ajax' ) );
|
143 |
+
|
144 |
+
$subs_version = class_exists( 'WC_Subscriptions' ) && ! empty( WC_Subscriptions::$version ) ? WC_Subscriptions::$version : null;
|
145 |
+
|
146 |
+
// Prevent data being copied to subscriptions.
|
147 |
+
if ( null !== $subs_version && version_compare( $subs_version, '2.0.0', '>=' ) ) {
|
148 |
+
add_filter( 'wcs_renewal_order_meta_query', array( $this->actions, 'woocommerce_subscriptions_renewal_order_meta_query' ), 10, 4 );
|
149 |
+
} else {
|
150 |
+
add_filter( 'woocommerce_subscriptions_renewal_order_meta_query', array( $this->actions, 'woocommerce_subscriptions_renewal_order_meta_query' ), 10, 4 );
|
151 |
+
}
|
152 |
+
|
153 |
+
// Add api key config on user profile.
|
154 |
+
add_action( 'show_user_profile', array( $this->actions, 'add_api_key_field' ) );
|
155 |
+
add_action( 'edit_user_profile', array( $this->actions, 'add_api_key_field' ) );
|
156 |
+
add_action( 'personal_options_update', array( $this->actions, 'generate_api_key' ) );
|
157 |
+
add_action( 'edit_user_profile_update', array( $this->actions, 'generate_api_key' ) );
|
158 |
+
}
|
159 |
+
|
160 |
+
|
161 |
+
/**
|
162 |
+
* Get selected couriers
|
163 |
+
*
|
164 |
+
* @return array
|
165 |
+
*/
|
166 |
+
public function get_selected_couriers() {
|
167 |
+
$slugs = explode( ',', $this->options['couriers'] );
|
168 |
+
$selected_couriers = array();
|
169 |
+
foreach ( $this->couriers as $courier ) {
|
170 |
+
if ( in_array( $courier['slug'], $slugs, true ) ) {
|
171 |
+
$selected_couriers[] = $courier;
|
172 |
+
}
|
173 |
+
}
|
174 |
+
return $selected_couriers;
|
175 |
+
}
|
176 |
+
|
177 |
+
/**
|
178 |
+
* Include required files.
|
179 |
+
*
|
180 |
+
* @since 1.4.0
|
181 |
+
*/
|
182 |
+
private function includes() {
|
183 |
+
require( $this->plugin_dir . '/includes/class-aftership-actions.php' );
|
184 |
+
$this->actions = AfterShip_Actions::get_instance();
|
185 |
+
require( $this->plugin_dir . '/includes/api/class-aftership-api.php' );
|
186 |
+
$this->api = new AfterShip_API();
|
187 |
+
require_once( $this->plugin_dir . '/includes/class-aftership-settings.php' );
|
188 |
+
}
|
189 |
+
|
190 |
+
/**
|
191 |
+
* Gets the absolute plugin path without a trailing slash, e.g.
|
192 |
+
* /path/to/wp-content/plugins/plugin-directory.
|
193 |
+
*
|
194 |
+
* @return string plugin path
|
195 |
+
*/
|
196 |
+
public function get_plugin_path() {
|
197 |
+
if ( isset( $this->plugin_path ) ) {
|
198 |
+
return $this->plugin_path;
|
199 |
+
}
|
200 |
+
|
201 |
+
$this->plugin_path = untrailingslashit( plugin_dir_path( __FILE__ ) );
|
202 |
+
|
203 |
+
return $this->plugin_path;
|
204 |
+
}
|
205 |
+
}
|
206 |
+
|
207 |
+
} // End if().
|
208 |
+
|
209 |
+
/**
|
210 |
+
* Returns an instance of AfterShip.
|
211 |
+
*
|
212 |
+
* @return AfterShip
|
213 |
+
*/
|
214 |
+
function aftership() {
|
215 |
+
static $instance;
|
216 |
+
|
217 |
+
if ( ! isset( $instance ) ) {
|
218 |
+
$instance = new AfterShip();
|
219 |
+
}
|
220 |
+
|
221 |
+
return $instance;
|
222 |
+
}
|
223 |
+
|
224 |
+
/**
|
225 |
+
* Register this class globally.
|
226 |
+
*
|
227 |
+
* Backward compatibility.
|
228 |
+
*/
|
229 |
+
$GLOBALS['AfterShip'] = aftership();
|
230 |
+
} // End if().
|
aftership.php
CHANGED
@@ -1,608 +1,16 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
|
4 |
-
|
5 |
-
|
6 |
-
|
7 |
-
|
8 |
-
|
9 |
-
|
10 |
-
|
11 |
-
|
12 |
-
|
13 |
-
|
14 |
-
|
15 |
-
|
16 |
-
|
17 |
-
|
18 |
-
/**
|
19 |
-
* Required functions
|
20 |
-
*/
|
21 |
-
if (!function_exists('is_woocommerce_active'))
|
22 |
-
require_once('aftership-functions.php');
|
23 |
-
require_once('aftership-backward-compatibility.php');
|
24 |
-
|
25 |
-
/**
|
26 |
-
* Plugin updates
|
27 |
-
*/
|
28 |
-
|
29 |
-
if (is_woocommerce_active()) {
|
30 |
-
|
31 |
-
/**
|
32 |
-
* AfterShip class
|
33 |
-
*/
|
34 |
-
if (!class_exists('AfterShip')) {
|
35 |
-
|
36 |
-
final class AfterShip
|
37 |
-
{
|
38 |
-
|
39 |
-
protected static $_instance = null;
|
40 |
-
|
41 |
-
public static function instance()
|
42 |
-
{
|
43 |
-
if (is_null(self::$_instance)) {
|
44 |
-
self::$_instance = new self();
|
45 |
-
}
|
46 |
-
return self::$_instance;
|
47 |
-
}
|
48 |
-
|
49 |
-
|
50 |
-
/**
|
51 |
-
* Constructor
|
52 |
-
*/
|
53 |
-
public function __construct()
|
54 |
-
{
|
55 |
-
$this->includes();
|
56 |
-
|
57 |
-
$this->api = new AfterShip_API();
|
58 |
-
|
59 |
-
$options = get_option('aftership_option_name');
|
60 |
-
if ($options) {
|
61 |
-
|
62 |
-
if (isset($options['plugin'])) {
|
63 |
-
$plugin = $options['plugin'];
|
64 |
-
if ($plugin == 'aftership') {
|
65 |
-
add_action('admin_print_scripts', array(&$this, 'library_scripts'));
|
66 |
-
add_action('in_admin_footer', array(&$this, 'include_footer_script'));
|
67 |
-
add_action('admin_print_styles', array(&$this, 'admin_styles'));
|
68 |
-
add_action('add_meta_boxes', array(&$this, 'add_meta_box'));
|
69 |
-
add_action('woocommerce_process_shop_order_meta', array(&$this, 'save_meta_box'), 0, 2);
|
70 |
-
add_action('plugins_loaded', array($this, 'load_plugin_textdomain'));
|
71 |
-
|
72 |
-
$this->couriers = $options['couriers'];
|
73 |
-
}
|
74 |
-
|
75 |
-
// View Order Page
|
76 |
-
$this->plugin = $plugin;
|
77 |
-
} else {
|
78 |
-
$this->plugin = '';
|
79 |
-
}
|
80 |
-
|
81 |
-
if (isset($options['use_track_button'])) {
|
82 |
-
$this->use_track_button = $options['use_track_button'];
|
83 |
-
} else {
|
84 |
-
$this->use_track_button = false;
|
85 |
-
}
|
86 |
-
|
87 |
-
if (isset($options['custom_domain'])) {
|
88 |
-
$this->custom_domain = $options['custom_domain'];
|
89 |
-
} else {
|
90 |
-
$this->custom_domain = '';
|
91 |
-
}
|
92 |
-
|
93 |
-
add_action('woocommerce_view_order', array(&$this, 'display_tracking_info'));
|
94 |
-
add_action('woocommerce_email_before_order_table', array(&$this, 'email_display'));
|
95 |
-
|
96 |
-
}
|
97 |
-
|
98 |
-
// user profile api key
|
99 |
-
add_action('show_user_profile', array($this, 'add_api_key_field'));
|
100 |
-
add_action('edit_user_profile', array($this, 'add_api_key_field'));
|
101 |
-
add_action('personal_options_update', array($this, 'generate_api_key'));
|
102 |
-
add_action('edit_user_profile_update', array($this, 'generate_api_key'));
|
103 |
-
|
104 |
-
register_activation_hook(__FILE__, array($this, 'install'));
|
105 |
-
}
|
106 |
-
|
107 |
-
public function install()
|
108 |
-
{
|
109 |
-
global $wp_roles;
|
110 |
-
|
111 |
-
if (class_exists('WP_Roles')) {
|
112 |
-
if (!isset($wp_roles)) {
|
113 |
-
$wp_roles = new WP_Roles();
|
114 |
-
}
|
115 |
-
}
|
116 |
-
|
117 |
-
if (is_object($wp_roles)) {
|
118 |
-
$wp_roles->add_cap('administrator', 'manage_aftership');
|
119 |
-
}
|
120 |
-
}
|
121 |
-
|
122 |
-
private function includes()
|
123 |
-
{
|
124 |
-
include_once('aftership-fields.php');
|
125 |
-
$this->aftership_fields = $aftership_fields;
|
126 |
-
|
127 |
-
include_once('class-aftership-api.php');
|
128 |
-
include_once('class-aftership-settings.php');
|
129 |
-
}
|
130 |
-
|
131 |
-
/**
|
132 |
-
* Localisation
|
133 |
-
*/
|
134 |
-
public function load_plugin_textdomain()
|
135 |
-
{
|
136 |
-
load_plugin_textdomain('aftership', false, dirname(plugin_basename(__FILE__)) . '/languages/');
|
137 |
-
}
|
138 |
-
|
139 |
-
public function admin_styles()
|
140 |
-
{
|
141 |
-
wp_enqueue_style('aftership_styles_chosen', plugins_url(basename(dirname(__FILE__))) . '/assets/plugin/chosen/chosen.min.css');
|
142 |
-
wp_enqueue_style('aftership_styles', plugins_url(basename(dirname(__FILE__))) . '/assets/css/admin.css');
|
143 |
-
}
|
144 |
-
|
145 |
-
public function library_scripts()
|
146 |
-
{
|
147 |
-
wp_enqueue_script('aftership_styles_chosen_jquery', plugins_url(basename(dirname(__FILE__))) . '/assets/plugin/chosen/chosen.jquery.min.js');
|
148 |
-
wp_enqueue_script('aftership_styles_chosen_proto', plugins_url(basename(dirname(__FILE__))) . '/assets/plugin/chosen/chosen.proto.min.js');
|
149 |
-
wp_enqueue_script('aftership_script_util', plugins_url(basename(dirname(__FILE__))) . '/assets/js/util.js');
|
150 |
-
wp_enqueue_script('aftership_script_couriers', plugins_url(basename(dirname(__FILE__))) . '/assets/js/couriers.js');
|
151 |
-
wp_enqueue_script('aftership_script_admin', plugins_url(basename(dirname(__FILE__))) . '/assets/js/admin.js');
|
152 |
-
}
|
153 |
-
public function include_footer_script()
|
154 |
-
{
|
155 |
-
wp_enqueue_script('aftership_script_footer', plugins_url(basename(dirname(__FILE__))) . '/assets/js/footer.js', true);
|
156 |
-
}
|
157 |
-
|
158 |
-
/**
|
159 |
-
* Add the meta box for shipment info on the order page
|
160 |
-
*
|
161 |
-
* @access public
|
162 |
-
*/
|
163 |
-
public function add_meta_box()
|
164 |
-
{
|
165 |
-
add_meta_box('woocommerce-aftership', __('AfterShip', 'wc_aftership'), array(&$this, 'meta_box'), 'shop_order', 'side', 'high');
|
166 |
-
}
|
167 |
-
|
168 |
-
/**
|
169 |
-
* Show the meta box for shipment info on the order page
|
170 |
-
*
|
171 |
-
* @access public
|
172 |
-
*/
|
173 |
-
public function meta_box()
|
174 |
-
{
|
175 |
-
|
176 |
-
// just draw the layout, no data
|
177 |
-
global $post;
|
178 |
-
|
179 |
-
$selected_provider = get_post_meta($post->ID, '_aftership_tracking_provider', true);
|
180 |
-
|
181 |
-
echo '<div id="aftership_wrapper">';
|
182 |
-
|
183 |
-
echo '<p class="form-field"><label for="aftership_tracking_provider">' . __('Carrier:', 'wc_aftership') . '</label><br/><select id="aftership_tracking_provider" name="aftership_tracking_provider" class="chosen_select" style="width:100%">';
|
184 |
-
if ($selected_provider == '') {
|
185 |
-
$selected_text = 'selected="selected"';
|
186 |
-
} else {
|
187 |
-
$selected_text = '';
|
188 |
-
}
|
189 |
-
echo '<option disabled ' . $selected_text . ' value="">Please Select</option>';
|
190 |
-
echo '</select>';
|
191 |
-
echo '<br><a href="options-general.php?page=aftership-setting-admin">Update carrier list</a>';
|
192 |
-
echo '<input type="hidden" id="aftership_tracking_provider_hidden" value="' . $selected_provider . '"/>';
|
193 |
-
echo '<input type="hidden" id="aftership_couriers_selected" value="' . $this->couriers . '"/>';
|
194 |
-
|
195 |
-
foreach ($this->aftership_fields as $field) {
|
196 |
-
if ($field['type'] == 'date') {
|
197 |
-
woocommerce_wp_text_input(array(
|
198 |
-
'id' => $field['id'],
|
199 |
-
'label' => __($field['label'], 'wc_aftership'),
|
200 |
-
'placeholder' => $field['placeholder'],
|
201 |
-
'description' => $field['description'],
|
202 |
-
'class' => $field['class'],
|
203 |
-
'value' => ($date = get_post_meta($post->ID, '_' . $field['id'], true)) ? date('Y-m-d', $date) : ''
|
204 |
-
));
|
205 |
-
} else {
|
206 |
-
woocommerce_wp_text_input(array(
|
207 |
-
'id' => $field['id'],
|
208 |
-
'label' => __($field['label'], 'wc_aftership'),
|
209 |
-
'placeholder' => $field['placeholder'],
|
210 |
-
'description' => $field['description'],
|
211 |
-
'class' => $field['class'],
|
212 |
-
'value' => get_post_meta($post->ID, '_' . $field['id'], true),
|
213 |
-
));
|
214 |
-
}
|
215 |
-
}
|
216 |
-
|
217 |
-
//
|
218 |
-
// woocommerce_wp_text_input(array(
|
219 |
-
// 'id' => 'aftership_tracking_provider_name',
|
220 |
-
// 'label' => __('', 'wc_aftership'),
|
221 |
-
// 'placeholder' => '',
|
222 |
-
// 'description' => '',
|
223 |
-
// 'class' => 'hidden',
|
224 |
-
// 'value' => get_post_meta($post->ID, '_aftership_tracking_provider_name', true),
|
225 |
-
// ));
|
226 |
-
//
|
227 |
-
// woocommerce_wp_text_input(array(
|
228 |
-
// 'id' => 'aftership_tracking_required_fields',
|
229 |
-
// 'label' => __('', 'wc_aftership'),
|
230 |
-
// 'placeholder' => '',
|
231 |
-
// 'description' => '',
|
232 |
-
// 'class' => 'hidden',
|
233 |
-
// 'value' => get_post_meta($post->ID, '_aftership_tracking_required_fields', true),
|
234 |
-
// ));
|
235 |
-
//
|
236 |
-
// woocommerce_wp_text_input(array(
|
237 |
-
// 'id' => 'aftership_tracking_number',
|
238 |
-
// 'label' => __('Tracking number:', 'wc_aftership'),
|
239 |
-
// 'placeholder' => '',
|
240 |
-
// 'description' => '',
|
241 |
-
// 'value' => get_post_meta($post->ID, '_aftership_tracking_number', true),
|
242 |
-
// ));
|
243 |
-
//
|
244 |
-
// woocommerce_wp_text_input(array(
|
245 |
-
// 'id' => 'aftership_tracking_shipdate',
|
246 |
-
// 'label' => __('Date shipped:', 'wc_aftership'),
|
247 |
-
// 'placeholder' => 'YYYY-MM-DD',
|
248 |
-
// 'description' => '',
|
249 |
-
// 'class' => 'date-picker-field hidden-field',
|
250 |
-
// 'value' => ($date = get_post_meta($post->ID, '_aftership_tracking_shipdate', true)) ? date('Y-m-d', $date) : ''
|
251 |
-
// ));
|
252 |
-
//
|
253 |
-
// woocommerce_wp_text_input(array(
|
254 |
-
// 'id' => 'aftership_tracking_postal',
|
255 |
-
// 'label' => __('Postal Code:', 'wc_aftership'),
|
256 |
-
// 'placeholder' => '',
|
257 |
-
// 'description' => '',
|
258 |
-
// 'class' => 'hidden-field',
|
259 |
-
// 'value' => get_post_meta($post->ID, '_aftership_tracking_postal', true),
|
260 |
-
// ));
|
261 |
-
//
|
262 |
-
// woocommerce_wp_text_input(array(
|
263 |
-
// 'id' => 'aftership_tracking_account',
|
264 |
-
// 'label' => __('Account name:', 'wc_aftership'),
|
265 |
-
// 'placeholder' => '',
|
266 |
-
// 'description' => '',
|
267 |
-
// 'class' => 'hidden-field',
|
268 |
-
// 'value' => get_post_meta($post->ID, '_aftership_tracking_account', true),
|
269 |
-
// ));
|
270 |
-
//
|
271 |
-
// woocommerce_wp_text_input(array(
|
272 |
-
// 'id' => 'aftership_tracking_key',
|
273 |
-
// 'label' => __('Tracking key:', 'wc_aftership'),
|
274 |
-
// 'placeholder' => '',
|
275 |
-
// 'description' => '',
|
276 |
-
// 'class' => 'hidden-field',
|
277 |
-
// 'value' => get_post_meta($post->ID, '_aftership_tracking_key', true),
|
278 |
-
// ));
|
279 |
-
//
|
280 |
-
// woocommerce_wp_text_input(array(
|
281 |
-
// 'id' => 'aftership_tracking_destination_country',
|
282 |
-
// 'label' => __('Destination Country:', 'wc_aftership'),
|
283 |
-
// 'placeholder' => '',
|
284 |
-
// 'description' => '',
|
285 |
-
// 'class' => 'hidden-field',
|
286 |
-
// 'value' => get_post_meta($post->ID, '_aftership_tracking_destination_country', true),
|
287 |
-
// ));
|
288 |
-
echo '</div>';
|
289 |
-
}
|
290 |
-
|
291 |
-
/**
|
292 |
-
* Order Downloads Save
|
293 |
-
*
|
294 |
-
* Function for processing and storing all order downloads.
|
295 |
-
*/
|
296 |
-
public function save_meta_box($post_id, $post)
|
297 |
-
{
|
298 |
-
if (isset($_POST['aftership_tracking_number'])) {
|
299 |
-
//
|
300 |
-
// // Download data
|
301 |
-
$tracking_provider = wc_clean($_POST['aftership_tracking_provider']);
|
302 |
-
// $tracking_number = wc_clean($_POST['aftership_tracking_number']);
|
303 |
-
// $tracking_provider_name = wc_clean($_POST['aftership_tracking_provider_name']);
|
304 |
-
// $tracking_required_fields = wc_clean($_POST['aftership_tracking_required_fields']);
|
305 |
-
// $shipdate = wc_clean(strtotime($_POST['aftership_tracking_shipdate']));
|
306 |
-
// $postal = wc_clean($_POST['aftership_tracking_postal']);
|
307 |
-
// $account = wc_clean($_POST['aftership_tracking_account']);
|
308 |
-
// $tracking_key = wc_clean($_POST['aftership_tracking_key']);
|
309 |
-
// $tracking_destination_country = wc_clean($_POST['aftership_tracking_destination_country']);
|
310 |
-
//
|
311 |
-
// // Update order data
|
312 |
-
update_post_meta($post_id, '_aftership_tracking_provider', $tracking_provider);
|
313 |
-
// update_post_meta($post_id, '_aftership_tracking_number', $tracking_number);
|
314 |
-
// update_post_meta($post_id, '_aftership_tracking_provider_name', $tracking_provider_name);
|
315 |
-
// update_post_meta($post_id, '_aftership_tracking_required_fields', $tracking_required_fields);
|
316 |
-
// update_post_meta($post_id, '_aftership_tracking_shipdate', $shipdate);
|
317 |
-
// update_post_meta($post_id, '_aftership_tracking_postal', $postal);
|
318 |
-
// update_post_meta($post_id, '_aftership_tracking_account', $account);
|
319 |
-
// update_post_meta($post_id, '_aftership_tracking_key', $tracking_key);
|
320 |
-
// update_post_meta($post_id, '_aftership_tracking_destination_country', $tracking_destination_country);
|
321 |
-
|
322 |
-
|
323 |
-
foreach ($this->aftership_fields as $field) {
|
324 |
-
if ($field['type'] == 'date') {
|
325 |
-
update_post_meta($post_id, '_' . $field['id'], wc_clean(strtotime($_POST[$field['id']])));
|
326 |
-
} else {
|
327 |
-
update_post_meta($post_id, '_' . $field['id'], wc_clean($_POST[$field['id']]));
|
328 |
-
}
|
329 |
-
}
|
330 |
-
}
|
331 |
-
}
|
332 |
-
|
333 |
-
/**
|
334 |
-
* Display the API key info for a user
|
335 |
-
*
|
336 |
-
* @since 2.1
|
337 |
-
* @param WP_User $user
|
338 |
-
*/
|
339 |
-
public function add_api_key_field($user)
|
340 |
-
{
|
341 |
-
|
342 |
-
if (!current_user_can('manage_aftership'))
|
343 |
-
return;
|
344 |
-
|
345 |
-
if (current_user_can('edit_user', $user->ID)) {
|
346 |
-
?>
|
347 |
-
<h3>AfterShip</h3>
|
348 |
-
<table class="form-table">
|
349 |
-
<tbody>
|
350 |
-
<tr>
|
351 |
-
<th><label
|
352 |
-
for="aftership_wp_api_key"><?php _e('AfterShip\'s WordPress API Key', 'aftership'); ?></label>
|
353 |
-
</th>
|
354 |
-
<td>
|
355 |
-
<?php if (empty($user->aftership_wp_api_key)) : ?>
|
356 |
-
<input name="aftership_wp_generate_api_key" type="checkbox"
|
357 |
-
id="aftership_wp_generate_api_key" value="0"/>
|
358 |
-
<span class="description"><?php _e('Generate API Key', 'aftership'); ?></span>
|
359 |
-
<?php else : ?>
|
360 |
-
<code id="aftership_wp_api_key"><?php echo $user->aftership_wp_api_key ?></code>
|
361 |
-
<br/>
|
362 |
-
<input name="aftership_wp_generate_api_key" type="checkbox"
|
363 |
-
id="aftership_wp_generate_api_key" value="0"/>
|
364 |
-
<span class="description"><?php _e('Revoke API Key', 'aftership'); ?></span>
|
365 |
-
<?php endif; ?>
|
366 |
-
</td>
|
367 |
-
</tr>
|
368 |
-
</tbody>
|
369 |
-
</table>
|
370 |
-
<?php
|
371 |
-
}
|
372 |
-
}
|
373 |
-
|
374 |
-
/**
|
375 |
-
* Generate and save (or delete) the API keys for a user
|
376 |
-
*
|
377 |
-
* @since 2.1
|
378 |
-
* @param int $user_id
|
379 |
-
*/
|
380 |
-
public function generate_api_key($user_id)
|
381 |
-
{
|
382 |
-
|
383 |
-
if (current_user_can('edit_user', $user_id)) {
|
384 |
-
|
385 |
-
$user = get_userdata($user_id);
|
386 |
-
|
387 |
-
// creating/deleting key
|
388 |
-
if (isset($_POST['aftership_wp_generate_api_key'])) {
|
389 |
-
|
390 |
-
// consumer key
|
391 |
-
if (empty($user->aftership_wp_api_key)) {
|
392 |
-
|
393 |
-
$api_key = 'ck_' . hash('md5', $user->user_login . date('U') . mt_rand());
|
394 |
-
|
395 |
-
update_user_meta($user_id, 'aftership_wp_api_key', $api_key);
|
396 |
-
|
397 |
-
} else {
|
398 |
-
|
399 |
-
delete_user_meta($user_id, 'aftership_wp_api_key');
|
400 |
-
}
|
401 |
-
|
402 |
-
}
|
403 |
-
}
|
404 |
-
}
|
405 |
-
|
406 |
-
/**
|
407 |
-
* Display Shipment info in the frontend (order view/tracking page).
|
408 |
-
*
|
409 |
-
* @access public
|
410 |
-
*/
|
411 |
-
function display_tracking_info($order_id, $for_email = false)
|
412 |
-
{
|
413 |
-
if ($this->plugin == 'aftership') {
|
414 |
-
$this->display_order_aftership($order_id, $for_email);
|
415 |
-
} else if ($this->plugin == 'wc-shipment-tracking') { //$49
|
416 |
-
$this->display_order_wc_shipment_tracking($order_id, $for_email);
|
417 |
-
}
|
418 |
-
}
|
419 |
-
|
420 |
-
private function display_order_aftership($order_id, $for_email)
|
421 |
-
{
|
422 |
-
|
423 |
-
// print_r($this->aftership_fields);
|
424 |
-
$values = array();
|
425 |
-
foreach ($this->aftership_fields as $field) {
|
426 |
-
$values[$field['id']] = get_post_meta($order_id, '_' . $field['id'], true);
|
427 |
-
if ($field['type'] == 'date' && $values[$field['id']]) {
|
428 |
-
$values[$field['id']] = date_i18n(__('l jS F Y', 'wc_shipment_tracking'), $values[$field['id']]);
|
429 |
-
}
|
430 |
-
}
|
431 |
-
$values['aftership_tracking_provider'] = get_post_meta($order_id, '_aftership_tracking_provider', true);
|
432 |
-
|
433 |
-
if (!$values['aftership_tracking_provider'])
|
434 |
-
return;
|
435 |
-
|
436 |
-
if (!$values['aftership_tracking_number'])
|
437 |
-
return;
|
438 |
-
|
439 |
-
|
440 |
-
$options = get_option('aftership_option_name');
|
441 |
-
if (array_key_exists('track_message_1', $options) && array_key_exists('track_message_2', $options)) {
|
442 |
-
$track_message_1 = $options['track_message_1'];
|
443 |
-
$track_message_2 = $options['track_message_2'];
|
444 |
-
} else {
|
445 |
-
$track_message_1 = 'Your order was shipped via ';
|
446 |
-
$track_message_2 = 'Tracking number is ';
|
447 |
-
}
|
448 |
-
|
449 |
-
$required_fields_values = array();
|
450 |
-
$provider_required_fields = explode(",", $values['aftership_tracking_required_fields']);
|
451 |
-
|
452 |
-
for ($i = 0 ; $i < count($provider_required_fields); $i++) {
|
453 |
-
$field = $provider_required_fields[$i];
|
454 |
-
foreach ($this->aftership_fields as $aftership_field) {
|
455 |
-
if (array_key_exists('key', $aftership_field) && $field == $aftership_field['key']) {
|
456 |
-
array_unshift($required_fields_values, $values[$aftership_field['id']]);
|
457 |
-
}
|
458 |
-
}
|
459 |
-
}
|
460 |
-
|
461 |
-
if (count($required_fields_values)) {
|
462 |
-
$required_fields_msg = ' (' . join(', ', $required_fields_values) . ')';
|
463 |
-
} else {
|
464 |
-
$required_fields_msg = '';
|
465 |
-
}
|
466 |
-
|
467 |
-
|
468 |
-
echo $track_message_1 . $values['aftership_tracking_provider_name'] . '<br/>' . $track_message_2 . $values['aftership_tracking_number'] . $required_fields_msg;
|
469 |
-
|
470 |
-
if (!$for_email && $this->use_track_button) {
|
471 |
-
$this->display_track_button($values['aftership_tracking_provider'], $values['aftership_tracking_number'], $required_fields_values);
|
472 |
-
}
|
473 |
-
|
474 |
-
//-------------------------------------------------------------------------------------
|
475 |
-
/*
|
476 |
-
$tracking_provider = get_post_meta($order_id, '_aftership_tracking_provider', true);
|
477 |
-
$tracking_number = get_post_meta($order_id, '_aftership_tracking_number', true);
|
478 |
-
$tracking_provider_name = get_post_meta($order_id, '_aftership_tracking_provider_name', true);
|
479 |
-
$tracking_required_fields = get_post_meta($order_id, '_aftership_tracking_required_fields', true);
|
480 |
-
$date_shipped = get_post_meta($order_id, '_aftership_tracking_shipdate', true);
|
481 |
-
$postcode = get_post_meta($order_id, '_aftership_tracking_postal', true);
|
482 |
-
$account = get_post_meta($order_id, '_aftership_tracking_account', true);
|
483 |
-
|
484 |
-
if (!$tracking_provider)
|
485 |
-
return;
|
486 |
-
|
487 |
-
if (!$tracking_number)
|
488 |
-
return;
|
489 |
-
|
490 |
-
$provider_name = $tracking_provider_name;
|
491 |
-
$provider_required_fields = explode(",", $tracking_required_fields);
|
492 |
-
|
493 |
-
$date_shipped_str = '';
|
494 |
-
$postcode_str = '';
|
495 |
-
$account_str = '';
|
496 |
-
|
497 |
-
foreach ($provider_required_fields as $field) {
|
498 |
-
if ($field == 'tracking_ship_date') {
|
499 |
-
if ($date_shipped) {
|
500 |
-
$date_shipped_str = ' ' . sprintf(__('on %s', 'wc_shipment_tracking'), date_i18n(__('l jS F Y', 'wc_shipment_tracking'), $date_shipped));
|
501 |
-
}
|
502 |
-
} else if ($field == 'tracking_postal_code') {
|
503 |
-
if ($postcode) {
|
504 |
-
$postcode_str = ' ' . sprintf('The postal code is %s.', $postcode);
|
505 |
-
}
|
506 |
-
} else if ($field == 'tracking_account_number') {
|
507 |
-
if ($account) {
|
508 |
-
$account_str = ' ' . sprintf('The account is %s.', $account);
|
509 |
-
}
|
510 |
-
}
|
511 |
-
}
|
512 |
-
|
513 |
-
$provider_name = ' ' . __('via', 'wc_shipment_tracking') . ' <strong>' . $provider_name . '</strong>';
|
514 |
-
|
515 |
-
echo wpautop(sprintf(__('Your order was shipped%s%s. Tracking number is %s.%s%s', 'wc_shipment_tracking'), $date_shipped_str, $provider_name, $tracking_number, $postcode_str, $account_str));
|
516 |
-
|
517 |
-
if (!$for_email && $this->use_track_button) {
|
518 |
-
$this->display_track_button($tracking_provider, $tracking_number);
|
519 |
-
}
|
520 |
-
*/
|
521 |
-
|
522 |
-
}
|
523 |
-
|
524 |
-
private function display_order_wc_shipment_tracking($order_id, $for_email)
|
525 |
-
{
|
526 |
-
if ($for_email || !$this->use_track_button) {
|
527 |
-
return;
|
528 |
-
}
|
529 |
-
|
530 |
-
$tracking = get_post_meta($order_id, '_tracking_number', true);
|
531 |
-
$sharp = strpos($tracking, '#');
|
532 |
-
$colon = strpos($tracking, ':');
|
533 |
-
$required_fields = array();
|
534 |
-
if ($sharp && $colon && $sharp >= $colon) {
|
535 |
-
return;
|
536 |
-
} else if (!$sharp && $colon) {
|
537 |
-
return;
|
538 |
-
} else if ($sharp) {
|
539 |
-
$tracking_provider = substr($tracking, 0, $sharp);
|
540 |
-
if ($colon) {
|
541 |
-
$tracking_number = substr($tracking, $sharp + 1, $colon - $sharp - 1);
|
542 |
-
$temp = substr($tracking, $sharp + 1, strlen($tracking));
|
543 |
-
$required_fields = explode(':', $temp);
|
544 |
-
} else {
|
545 |
-
$tracking_number = substr($tracking, $sharp + 1, strlen($tracking));
|
546 |
-
}
|
547 |
-
} else {
|
548 |
-
$tracking_provider = '';
|
549 |
-
$tracking_number = $tracking;
|
550 |
-
}
|
551 |
-
if ($tracking_number) {
|
552 |
-
$this->display_track_button($tracking_provider, $tracking_number, $required_fields);
|
553 |
-
}
|
554 |
-
}
|
555 |
-
|
556 |
-
/**
|
557 |
-
* Display shipment info in customer emails.
|
558 |
-
*
|
559 |
-
* @access public
|
560 |
-
* @return void
|
561 |
-
*/
|
562 |
-
function email_display($order)
|
563 |
-
{
|
564 |
-
$this->display_tracking_info(get_order_id($order), true);
|
565 |
-
}
|
566 |
-
|
567 |
-
private function display_track_button($tracking_provider, $tracking_number, $required_fields_values)
|
568 |
-
{
|
569 |
-
|
570 |
-
$js = '(function(e,t,n){var r,i=e.getElementsByTagName(t)[0];if(e.getElementById(n))return;r=e.createElement(t);r.id=n;r.src="//apps.aftership.com/all.js";i.parentNode.insertBefore(r,i)})(document,"script","aftership-jssdk")';
|
571 |
-
if (function_exists('wc_enqueue_js')) {
|
572 |
-
wc_enqueue_js($js);
|
573 |
-
} else {
|
574 |
-
global $woocommerce;
|
575 |
-
$woocommerce->add_inline_js($js);
|
576 |
-
}
|
577 |
-
|
578 |
-
if (count($required_fields_values)) {
|
579 |
-
$tracking_number = $tracking_number . ':' . join(':', $required_fields_values);
|
580 |
-
}
|
581 |
-
|
582 |
-
$temp_url = '';
|
583 |
-
$temp_slug = ' data-slug="' . $tracking_provider . '"';
|
584 |
-
if($this->custom_domain != '') {
|
585 |
-
$temp_url = '" data-domain="' . $this->custom_domain;
|
586 |
-
$temp_slug = '';
|
587 |
-
}
|
588 |
-
|
589 |
-
$track_button = '<div id="as-root"></div><div class="as-track-button"' . $temp_slug . ' data-tracking-number="' . $tracking_number . $temp_url .'" data-support="true" data-width="400" data-size="normal" data-hide-tracking-number="true"></div>';
|
590 |
-
echo wpautop(sprintf('%s', $track_button));
|
591 |
-
echo "<br><br>";
|
592 |
-
}
|
593 |
-
}
|
594 |
-
|
595 |
-
if (!function_exists('getAfterShipInstance')) {
|
596 |
-
function getAfterShipInstance()
|
597 |
-
{
|
598 |
-
return AfterShip::Instance();
|
599 |
-
}
|
600 |
-
}
|
601 |
-
}
|
602 |
-
|
603 |
-
/**
|
604 |
-
* Register this class globally
|
605 |
-
*/
|
606 |
-
$GLOBALS['aftership'] = getAfterShipInstance();
|
607 |
-
|
608 |
-
}
|
1 |
+
<?php
|
2 |
+
if ( ! defined( 'ABSPATH' ) ) {
|
3 |
+
exit;
|
4 |
+
}
|
5 |
+
|
6 |
+
/**
|
7 |
+
* Backwards compat.
|
8 |
+
*/
|
9 |
+
|
10 |
+
$active_plugins = get_option( 'active_plugins', array() );
|
11 |
+
foreach ( $active_plugins as $key => $active_plugin ) {
|
12 |
+
if ( strstr( $active_plugin, '/aftership.php' ) ) {
|
13 |
+
$active_plugins[ $key ] = str_replace( '/aftership.php', '/aftership-woocommerce-tracking.php', $active_plugin );
|
14 |
+
}
|
15 |
+
}
|
16 |
+
update_option( 'active_plugins', $active_plugins );
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
api/class-aftership-api-authentication.php
DELETED
@@ -1,129 +0,0 @@
|
|
1 |
-
<?php
|
2 |
-
/**
|
3 |
-
* AfterShip API Authentication Class
|
4 |
-
*
|
5 |
-
* @author AfterShip
|
6 |
-
* @category API
|
7 |
-
* @package AfterShip/API
|
8 |
-
* @since 1
|
9 |
-
*/
|
10 |
-
|
11 |
-
if (!defined('ABSPATH')) exit; // Exit if accessed directly
|
12 |
-
|
13 |
-
|
14 |
-
if (!function_exists('getallheaders')) {
|
15 |
-
function getallheaders()
|
16 |
-
{
|
17 |
-
$headers = '';
|
18 |
-
foreach ($_SERVER as $name => $value) {
|
19 |
-
if (substr($name, 0, 5) == 'HTTP_') {
|
20 |
-
$headers[str_replace(' ', '-', ucwords(strtolower(str_replace('_', ' ', substr($name, 5)))))] = $value;
|
21 |
-
}
|
22 |
-
}
|
23 |
-
return $headers;
|
24 |
-
}
|
25 |
-
}
|
26 |
-
|
27 |
-
class AfterShip_API_Authentication
|
28 |
-
{
|
29 |
-
|
30 |
-
/**
|
31 |
-
* Setup class
|
32 |
-
*
|
33 |
-
* @since 2.1
|
34 |
-
* @return WC_API_Authentication
|
35 |
-
*/
|
36 |
-
public function __construct()
|
37 |
-
{
|
38 |
-
|
39 |
-
// to disable authentication, hook into this filter at a later priority and return a valid WP_User
|
40 |
-
add_filter('aftership_api_check_authentication', array($this, 'authenticate'), 0);
|
41 |
-
}
|
42 |
-
|
43 |
-
/**
|
44 |
-
* Authenticate the request. The authentication method varies based on whether the request was made over SSL or not.
|
45 |
-
*
|
46 |
-
* @since 2.1
|
47 |
-
* @param WP_User $user
|
48 |
-
* @return null|WP_Error|WP_User
|
49 |
-
*/
|
50 |
-
public function authenticate($user)
|
51 |
-
{
|
52 |
-
|
53 |
-
// allow access to the index by default
|
54 |
-
if ('/' === getAfterShipInstance()->api->server->path)
|
55 |
-
return new WP_User(0);
|
56 |
-
|
57 |
-
try {
|
58 |
-
$user = $this->perform_authentication();
|
59 |
-
|
60 |
-
} catch (Exception $e) {
|
61 |
-
|
62 |
-
$user = new WP_Error('aftership_api_authentication_error', $e->getMessage(), array('status' => $e->getCode()));
|
63 |
-
}
|
64 |
-
|
65 |
-
return $user;
|
66 |
-
}
|
67 |
-
|
68 |
-
private function perform_authentication()
|
69 |
-
{
|
70 |
-
//$params = getAfterShipInstance()->api->server->params['GET'];
|
71 |
-
|
72 |
-
$headers = getallheaders();
|
73 |
-
$headers = json_decode(json_encode($headers), true);
|
74 |
-
|
75 |
-
// it dues to different kind of server configuration
|
76 |
-
$key = 'AFTERSHIP_WP_KEY';
|
77 |
-
$key1 = str_replace(' ', '-', ucwords(strtolower(str_replace('_', ' ', $key))));
|
78 |
-
$key2 = 'AFTERSHIP-WP-KEY';
|
79 |
-
$qskey = isset($_GET['key']) ? $_GET['key'] : null;
|
80 |
-
|
81 |
-
// get aftership wp key
|
82 |
-
if (!empty($headers[$key])) {
|
83 |
-
$api_key = $headers[$key];
|
84 |
-
} else if (!empty($headers[$key1])){
|
85 |
-
$api_key = $headers[$key1];
|
86 |
-
} else if (!empty($headers[$key2])){
|
87 |
-
$api_key = $headers[$key2];
|
88 |
-
} else if (!empty($qskey)) {
|
89 |
-
$api_key = $qskey;
|
90 |
-
} else {
|
91 |
-
throw new Exception(__('AfterShip\'s WordPress Key is missing', 'aftership'), 404);
|
92 |
-
}
|
93 |
-
|
94 |
-
$user = $this->get_user_by_api_key($api_key);
|
95 |
-
|
96 |
-
return $user;
|
97 |
-
|
98 |
-
}
|
99 |
-
|
100 |
-
/**
|
101 |
-
* Return the user for the given consumer key
|
102 |
-
*
|
103 |
-
* @since 2.1
|
104 |
-
* @param string $consumer_key
|
105 |
-
* @return WP_User
|
106 |
-
* @throws Exception
|
107 |
-
*/
|
108 |
-
private function get_user_by_api_key($api_key)
|
109 |
-
{
|
110 |
-
|
111 |
-
$user_query = new WP_User_Query(
|
112 |
-
array(
|
113 |
-
//'meta_key' => 'woocommerce_api_consumer_key',
|
114 |
-
'meta_key' => 'aftership_wp_api_key',
|
115 |
-
'meta_value' => $api_key,
|
116 |
-
)
|
117 |
-
);
|
118 |
-
|
119 |
-
$users = $user_query->get_results();
|
120 |
-
|
121 |
-
if (empty($users[0]))
|
122 |
-
throw new Exception(__('AfterShip\'s WordPress API Key is invalid', 'aftership'), 401);
|
123 |
-
|
124 |
-
return $users[0];
|
125 |
-
|
126 |
-
|
127 |
-
}
|
128 |
-
|
129 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
api/class-aftership-api-orders.php
DELETED
@@ -1,575 +0,0 @@
|
|
1 |
-
<?php
|
2 |
-
/**
|
3 |
-
* AfterShip API Orders Class
|
4 |
-
*
|
5 |
-
* Handles requests to the /orders endpoint
|
6 |
-
*
|
7 |
-
* @author AfterShip
|
8 |
-
* @category API
|
9 |
-
* @package AfterShip/API
|
10 |
-
* @since 1.0
|
11 |
-
*/
|
12 |
-
|
13 |
-
if (!defined('ABSPATH')) exit; // Exit if accessed directly
|
14 |
-
|
15 |
-
class AfterShip_API_Orders extends AfterShip_API_Resource
|
16 |
-
{
|
17 |
-
|
18 |
-
/** @var string $base the route base */
|
19 |
-
protected $base = '/orders';
|
20 |
-
|
21 |
-
/**
|
22 |
-
* Register the routes for this class
|
23 |
-
*
|
24 |
-
* GET /orders
|
25 |
-
* GET /orders/count
|
26 |
-
* GET|PUT /orders/<id>
|
27 |
-
* GET /orders/<id>/notes
|
28 |
-
*
|
29 |
-
* @since 2.1
|
30 |
-
* @param array $routes
|
31 |
-
* @return array
|
32 |
-
*/
|
33 |
-
public function register_routes($routes)
|
34 |
-
{
|
35 |
-
|
36 |
-
# GET /orders
|
37 |
-
$routes[$this->base] = array(
|
38 |
-
array(array($this, 'get_orders'), AfterShip_API_Server::READABLE),
|
39 |
-
);
|
40 |
-
|
41 |
-
# GET /orders/count
|
42 |
-
$routes[$this->base . '/count'] = array(
|
43 |
-
array(array($this, 'get_orders_count'), AfterShip_API_Server::READABLE),
|
44 |
-
);
|
45 |
-
|
46 |
-
# GET|PUT /orders/<id>
|
47 |
-
$routes[$this->base . '/(?P<id>\d+)'] = array(
|
48 |
-
array(array($this, 'get_order'), AfterShip_API_Server::READABLE),
|
49 |
-
array(array($this, 'edit_order'), AfterShip_API_Server::EDITABLE | AfterShip_API_Server::ACCEPT_DATA),
|
50 |
-
);
|
51 |
-
|
52 |
-
# GET /orders/<id>/notes
|
53 |
-
$routes[$this->base . '/(?P<id>\d+)/notes'] = array(
|
54 |
-
array(array($this, 'get_order_notes'), AfterShip_API_Server::READABLE),
|
55 |
-
);
|
56 |
-
|
57 |
-
# GET /orders/ping
|
58 |
-
$routes[$this->base . '/ping'] = array(
|
59 |
-
array(array($this, 'ping'), AfterShip_API_Server::READABLE),
|
60 |
-
);
|
61 |
-
|
62 |
-
return $routes;
|
63 |
-
}
|
64 |
-
|
65 |
-
/**
|
66 |
-
* Get all orders
|
67 |
-
*
|
68 |
-
* @since 2.1
|
69 |
-
* @param string $fields
|
70 |
-
* @param array $filter
|
71 |
-
* @param string $status
|
72 |
-
* @param int $page
|
73 |
-
* @return array
|
74 |
-
*/
|
75 |
-
public function get_orders($fields = null, $filter = array(), $status = null, $page = 1)
|
76 |
-
{
|
77 |
-
|
78 |
-
if (!empty($status))
|
79 |
-
$filter['status'] = $status;
|
80 |
-
|
81 |
-
$filter['page'] = $page;
|
82 |
-
|
83 |
-
$query = $this->query_orders($filter);
|
84 |
-
|
85 |
-
$orders = array();
|
86 |
-
|
87 |
-
foreach ($query->posts as $order_id) {
|
88 |
-
|
89 |
-
if (!$this->is_readable($order_id))
|
90 |
-
continue;
|
91 |
-
|
92 |
-
$orders[] = current($this->get_order($order_id, $fields));
|
93 |
-
}
|
94 |
-
|
95 |
-
$this->server->add_pagination_headers($query);
|
96 |
-
|
97 |
-
return array('orders' => $orders);
|
98 |
-
}
|
99 |
-
|
100 |
-
|
101 |
-
/**
|
102 |
-
* Get the order for the given ID
|
103 |
-
*
|
104 |
-
* @since 2.1
|
105 |
-
* @param int $id the order ID
|
106 |
-
* @param array $fields
|
107 |
-
* @return array
|
108 |
-
*/
|
109 |
-
public function get_order($id, $fields = null)
|
110 |
-
{
|
111 |
-
|
112 |
-
// ensure order ID is valid & user has permission to read
|
113 |
-
$id = $this->validate_request($id, 'shop_order', 'read');
|
114 |
-
|
115 |
-
if (is_wp_error($id))
|
116 |
-
return $id;
|
117 |
-
|
118 |
-
$order = new WC_Order($id);
|
119 |
-
|
120 |
-
$order_post = get_post($id);
|
121 |
-
|
122 |
-
$order_id = get_order_id($order);
|
123 |
-
|
124 |
-
$order_data = array(
|
125 |
-
'id' => get_order_id($order),
|
126 |
-
'order_number' => $order->get_order_number(),
|
127 |
-
'created_at' => $this->server->format_datetime($order_post->post_date_gmt),
|
128 |
-
'updated_at' => $this->server->format_datetime($order_post->post_modified_gmt),
|
129 |
-
// 'completed_at' => $this->server->format_datetime($order->completed_date, true),
|
130 |
-
// 'status' => $order->status,
|
131 |
-
// 'currency' => $order->order_currency,
|
132 |
-
// 'total' => wc_format_decimal($order->get_total(), 2),
|
133 |
-
// 'subtotal' => wc_format_decimal($this->get_order_subtotal($order), 2),
|
134 |
-
// 'total_line_items_quantity' => $order->get_item_count(),
|
135 |
-
// 'total_tax' => wc_format_decimal($order->get_total_tax(), 2),
|
136 |
-
// 'total_shipping' => wc_format_decimal($order->get_total_shipping(), 2),
|
137 |
-
// 'cart_tax' => wc_format_decimal($order->get_cart_tax(), 2),
|
138 |
-
// 'shipping_tax' => wc_format_decimal($order->get_shipping_tax(), 2),
|
139 |
-
// 'total_discount' => wc_format_decimal($order->get_total_discount(), 2),
|
140 |
-
// 'cart_discount' => wc_format_decimal($order->get_cart_discount(), 2),
|
141 |
-
// 'order_discount' => wc_format_decimal($order->get_order_discount(), 2),
|
142 |
-
// 'shipping_methods' => $order->get_shipping_method(),
|
143 |
-
// 'payment_details' => array(
|
144 |
-
// 'method_id' => $order->payment_method,
|
145 |
-
// 'method_title' => $order->payment_method_title,
|
146 |
-
// 'paid' => isset($order->paid_date),
|
147 |
-
// ),
|
148 |
-
'billing_address' => array(
|
149 |
-
'first_name' => order_post_meta_getter($order, 'billing_first_name'),
|
150 |
-
'last_name' => order_post_meta_getter($order, 'billing_last_name'),
|
151 |
-
'company' => order_post_meta_getter($order, 'billing_company'),
|
152 |
-
'address_1' => order_post_meta_getter($order, 'billing_address_1'),
|
153 |
-
'address_2' => order_post_meta_getter($order, 'billing_address_2'),
|
154 |
-
'city' => order_post_meta_getter($order, 'billing_city'),
|
155 |
-
'state' => order_post_meta_getter($order, 'billing_state'),
|
156 |
-
'postcode' => order_post_meta_getter($order, 'billing_postcode'),
|
157 |
-
'country' => order_post_meta_getter($order,'billing_country'),
|
158 |
-
'email' => order_post_meta_getter($order,'billing_email'),
|
159 |
-
'phone' => order_post_meta_getter($order,'billing_phone'),
|
160 |
-
),
|
161 |
-
'shipping_address' => array(
|
162 |
-
'first_name' => order_post_meta_getter($order,'shipping_first_name'),
|
163 |
-
'last_name' => order_post_meta_getter($order,'shipping_last_name'),
|
164 |
-
'company' => order_post_meta_getter($order,'shipping_company'),
|
165 |
-
'address_1' => order_post_meta_getter($order,'shipping_address_1'),
|
166 |
-
'address_2' => order_post_meta_getter($order,'shipping_address_2'),
|
167 |
-
'city' => order_post_meta_getter($order,'shipping_city'),
|
168 |
-
'state' => order_post_meta_getter($order,'shipping_state'),
|
169 |
-
'postcode' => order_post_meta_getter($order,'shipping_postcode'),
|
170 |
-
'country' => order_post_meta_getter($order,'shipping_country'),
|
171 |
-
),
|
172 |
-
'note' => (method_exists($order, 'get_customer_note'))? $order->get_customer_note() : $order->customer_note,
|
173 |
-
// 'customer_ip' => $order->customer_ip_address,
|
174 |
-
// 'customer_user_agent' => $order->customer_user_agent,
|
175 |
-
// 'customer_id' => $order->customer_user,
|
176 |
-
// 'view_order_url' => $order->get_view_order_url(),
|
177 |
-
'line_items' => array(),
|
178 |
-
// 'shipping_lines' => array(),
|
179 |
-
// 'tax_lines' => array(),
|
180 |
-
// 'fee_lines' => array(),
|
181 |
-
// 'coupon_lines' => array(),
|
182 |
-
'custom_fields' => array(),
|
183 |
-
'aftership' => array(
|
184 |
-
'woocommerce' => array(
|
185 |
-
'trackings' => array(
|
186 |
-
array(
|
187 |
-
'tracking_provider' => '',
|
188 |
-
'tracking_number' => '',
|
189 |
-
'tracking_ship_date' => '',
|
190 |
-
'tracking_postal_code' => '',
|
191 |
-
'tracking_account_number' => '',
|
192 |
-
'tracking_key' => '',
|
193 |
-
'tracking_destination_country' => '',
|
194 |
-
)
|
195 |
-
),
|
196 |
-
),
|
197 |
-
),
|
198 |
-
);
|
199 |
-
|
200 |
-
// add line items
|
201 |
-
foreach ($order->get_items() as $item_id => $item) {
|
202 |
-
|
203 |
-
// $product = $order->get_product_from_item($item);
|
204 |
-
|
205 |
-
$order_data['line_items'][] = array(
|
206 |
-
'id' => $item_id,
|
207 |
-
// 'subtotal' => wc_format_decimal($order->get_line_subtotal($item), 2),
|
208 |
-
// 'total' => wc_format_decimal($order->get_line_total($item), 2),
|
209 |
-
// 'total_tax' => wc_format_decimal($order->get_line_tax($item), 2),
|
210 |
-
// 'price' => wc_format_decimal($order->get_item_total($item), 2),
|
211 |
-
'quantity' => (int)$item['qty'],
|
212 |
-
// 'tax_class' => (!empty($item['tax_class'])) ? $item['tax_class'] : null,
|
213 |
-
'name' => $item['name'],
|
214 |
-
// 'product_id' => (isset($product->variation_id)) ? $product->variation_id : (method_exists($product, 'get_id'))? $product->get_id() : $product->id,
|
215 |
-
// 'sku' => is_object($product) ? $product->get_sku() : null,
|
216 |
-
);
|
217 |
-
}
|
218 |
-
|
219 |
-
/*
|
220 |
-
// add shipping
|
221 |
-
foreach ($order->get_shipping_methods() as $shipping_item_id => $shipping_item) {
|
222 |
-
|
223 |
-
$order_data['shipping_lines'][] = array(
|
224 |
-
'id' => $shipping_item_id,
|
225 |
-
'method_id' => $shipping_item['method_id'],
|
226 |
-
'method_title' => $shipping_item['name'],
|
227 |
-
'total' => wc_format_decimal($shipping_item['cost'], 2),
|
228 |
-
);
|
229 |
-
}
|
230 |
-
|
231 |
-
// add taxes
|
232 |
-
foreach ($order->get_tax_totals() as $tax_code => $tax) {
|
233 |
-
|
234 |
-
$order_data['tax_lines'][] = array(
|
235 |
-
'code' => $tax_code,
|
236 |
-
'title' => $tax->label,
|
237 |
-
'total' => wc_format_decimal($tax->amount, 2),
|
238 |
-
'compound' => (bool)$tax->is_compound,
|
239 |
-
);
|
240 |
-
}
|
241 |
-
|
242 |
-
// add fees
|
243 |
-
foreach ($order->get_fees() as $fee_item_id => $fee_item) {
|
244 |
-
|
245 |
-
$order_data['fee_lines'][] = array(
|
246 |
-
'id' => $fee_item_id,
|
247 |
-
'title' => $fee_item['name'],
|
248 |
-
'tax_class' => (!empty($fee_item['tax_class'])) ? $fee_item['tax_class'] : null,
|
249 |
-
'total' => wc_format_decimal($order->get_line_total($fee_item), 2),
|
250 |
-
'total_tax' => wc_format_decimal($order->get_line_tax($fee_item), 2),
|
251 |
-
);
|
252 |
-
}
|
253 |
-
|
254 |
-
// add coupons
|
255 |
-
foreach ($order->get_items('coupon') as $coupon_item_id => $coupon_item) {
|
256 |
-
|
257 |
-
$order_data['coupon_lines'][] = array(
|
258 |
-
'id' => $coupon_item_id,
|
259 |
-
'code' => $coupon_item['name'],
|
260 |
-
'amount' => wc_format_decimal($coupon_item['discount_amount'], 2),
|
261 |
-
);
|
262 |
-
}
|
263 |
-
*/
|
264 |
-
|
265 |
-
// aftership add
|
266 |
-
$aftership_tracking_number = order_post_meta_getter($order, 'aftership_tracking_number');
|
267 |
-
if (!empty($aftership_tracking_number)) {
|
268 |
-
|
269 |
-
// $result = array();
|
270 |
-
// foreach($this->aftership_fields as $field){
|
271 |
-
// $id = $field['id'];
|
272 |
-
// $result[substr($id,10)] = get_post_meta((method_exists($order, 'get_id'))? $order->get_id() : $order->id, '_' . $field['id'], true);
|
273 |
-
// }
|
274 |
-
// $order_data['aftership']['woocommerce']['trackings'][] = $result;
|
275 |
-
|
276 |
-
$order_data['aftership']['woocommerce']['trackings'][0] = array(
|
277 |
-
'tracking_provider' => order_post_meta_getter($order, 'aftership_tracking_provider'),
|
278 |
-
'tracking_number' => order_post_meta_getter($order, 'aftership_tracking_number'),
|
279 |
-
'tracking_ship_date' => order_post_meta_getter($order, 'aftership_tracking_shipdate'),
|
280 |
-
'tracking_postal_code' => order_post_meta_getter($order, 'aftership_tracking_postal'),
|
281 |
-
'tracking_account_number' => order_post_meta_getter($order, 'aftership_tracking_account'),
|
282 |
-
'tracking_key' => order_post_meta_getter($order, 'aftership_tracking_key'),
|
283 |
-
'tracking_destination_country' => order_post_meta_getter($order, 'aftership_tracking_destination_country'),
|
284 |
-
);
|
285 |
-
}
|
286 |
-
if ($tn == NULL) {
|
287 |
-
// Handle old Shipping Tracking plugin
|
288 |
-
$tn = order_post_meta_getter($order, 'tracking_number');
|
289 |
-
if ($tn == NULL) {
|
290 |
-
// Handle new Shipping Tracking plugin version higher than 1.6.4
|
291 |
-
$tracking_items = order_post_meta_getter($order, 'wc_shipment_tracking_items')[0];
|
292 |
-
|
293 |
-
|
294 |
-
if(!empty($tracking_items)) {
|
295 |
-
$order_data['aftership']['woocommerce']['trackings'][0] = array(
|
296 |
-
'tracking_number' => $tracking_items['tracking_number'],
|
297 |
-
'tracking_provider' => $tracking_items['custom_tracking_provider'],
|
298 |
-
'tracking_ship_date' => '',
|
299 |
-
'tracking_postal_code' => '',
|
300 |
-
'tracking_account_number' => '',
|
301 |
-
'tracking_key' => '',
|
302 |
-
'tracking_destination_country' => '',
|
303 |
-
);
|
304 |
-
// 获取 tracking_provider, tracking_postal_code
|
305 |
-
$trackingArr = $this->getTrackingInfoByShipmentTracking($tracking_items);
|
306 |
-
if(!empty($trackingArr)) {
|
307 |
-
$order_data['aftership']['woocommerce']['trackings'][0]['tracking_postal_code'] = $trackingArr['tracking_postal_code'];
|
308 |
-
$order_data['aftership']['woocommerce']['trackings'][0]['tracking_provider'] = $trackingArr['tracking_provider'];
|
309 |
-
}
|
310 |
-
}
|
311 |
-
} else {
|
312 |
-
$order_data['aftership']['woocommerce']['trackings'][0] = array(
|
313 |
-
'tracking_number' => $tn,
|
314 |
-
);
|
315 |
-
}
|
316 |
-
}
|
317 |
-
// aftership add finish
|
318 |
-
|
319 |
-
return array('order' => apply_filters('aftership_api_order_response', $order_data, $order, $fields, $this->server));
|
320 |
-
}
|
321 |
-
|
322 |
-
|
323 |
-
// 从wc ShipmentTracking 插件获取 Postalcode - postnl
|
324 |
-
private function getTrackingInfoByShipmentTracking($tracking_items) {
|
325 |
-
if(!isset($tracking_items['custom_tracking_link'])) {
|
326 |
-
return array();
|
327 |
-
}
|
328 |
-
|
329 |
-
// 获取 postnl Postalcode
|
330 |
-
$urlArr = parse_url(stripslashes($tracking_items['custom_tracking_link']));
|
331 |
-
|
332 |
-
if($urlArr === false) {
|
333 |
-
return array();
|
334 |
-
}
|
335 |
-
|
336 |
-
if (!isset($urlArr['host'])) {
|
337 |
-
return array();
|
338 |
-
}
|
339 |
-
|
340 |
-
$hostArr = explode(".", $urlArr['host']);
|
341 |
-
$hostArrIndex = count($hostArr) - 2;
|
342 |
-
if(empty($hostArr) || !isset($hostArr[$hostArrIndex])) {
|
343 |
-
return array();
|
344 |
-
}
|
345 |
-
|
346 |
-
if($hostArr[$hostArrIndex] == 'postnl') {
|
347 |
-
parse_str($urlArr['query'], $queryArr);
|
348 |
-
if(!isset($queryArr['Postalcode'])) {
|
349 |
-
return array();
|
350 |
-
}
|
351 |
-
|
352 |
-
return array(
|
353 |
-
'tracking_provider' => 'postnl',
|
354 |
-
'tracking_postal_code' => str_replace(" ", "", $queryArr['Postalcode']),
|
355 |
-
);
|
356 |
-
}
|
357 |
-
return array();
|
358 |
-
}
|
359 |
-
|
360 |
-
|
361 |
-
/**
|
362 |
-
* Get the total number of orders
|
363 |
-
*
|
364 |
-
* @since 2.1
|
365 |
-
* @param string $status
|
366 |
-
* @param array $filter
|
367 |
-
* @return array
|
368 |
-
*/
|
369 |
-
public function get_orders_count($status = null, $filter = array())
|
370 |
-
{
|
371 |
-
|
372 |
-
if (!empty($status))
|
373 |
-
$filter['status'] = $status;
|
374 |
-
|
375 |
-
$query = $this->query_orders($filter);
|
376 |
-
|
377 |
-
if (!current_user_can('read_private_shop_orders'))
|
378 |
-
return new WP_Error('aftership_api_user_cannot_read_orders_count', __('You do not have permission to read the orders count', 'aftership'), array('status' => 401));
|
379 |
-
|
380 |
-
return array('count' => (int)$query->found_posts);
|
381 |
-
}
|
382 |
-
|
383 |
-
/**
|
384 |
-
* Edit an order
|
385 |
-
*
|
386 |
-
* API v1 only allows updating the status of an order
|
387 |
-
*
|
388 |
-
* @since 2.1
|
389 |
-
* @param int $id the order ID
|
390 |
-
* @param array $data
|
391 |
-
* @return array
|
392 |
-
*/
|
393 |
-
public function edit_order($id, $data)
|
394 |
-
{
|
395 |
-
|
396 |
-
$id = $this->validate_request($id, 'shop_order', 'edit');
|
397 |
-
|
398 |
-
if (is_wp_error($id))
|
399 |
-
return $id;
|
400 |
-
|
401 |
-
$order = new WC_Order($id);
|
402 |
-
|
403 |
-
if (!empty($data['status'])) {
|
404 |
-
|
405 |
-
$order->update_status($data['status'], isset($data['note']) ? $data['note'] : '');
|
406 |
-
}
|
407 |
-
|
408 |
-
return $this->get_order($id);
|
409 |
-
}
|
410 |
-
|
411 |
-
/**
|
412 |
-
* Delete an order
|
413 |
-
*
|
414 |
-
* @TODO enable along with POST in 2.2
|
415 |
-
* @param int $id the order ID
|
416 |
-
* @param bool $force true to permanently delete order, false to move to trash
|
417 |
-
* @return array
|
418 |
-
*/
|
419 |
-
public function delete_order($id, $force = false)
|
420 |
-
{
|
421 |
-
|
422 |
-
$id = $this->validate_request($id, 'shop_order', 'delete');
|
423 |
-
|
424 |
-
return $this->delete($id, 'order', ('true' === $force));
|
425 |
-
}
|
426 |
-
|
427 |
-
/**
|
428 |
-
* Get the admin order notes for an order
|
429 |
-
*
|
430 |
-
* @since 2.1
|
431 |
-
* @param int $id the order ID
|
432 |
-
* @param string $fields fields to include in response
|
433 |
-
* @return array
|
434 |
-
*/
|
435 |
-
public function get_order_notes($id, $fields = null)
|
436 |
-
{
|
437 |
-
|
438 |
-
// ensure ID is valid order ID
|
439 |
-
$id = $this->validate_request($id, 'shop_order', 'read');
|
440 |
-
|
441 |
-
if (is_wp_error($id))
|
442 |
-
return $id;
|
443 |
-
|
444 |
-
$args = array(
|
445 |
-
'post_id' => $id,
|
446 |
-
'approve' => 'approve',
|
447 |
-
'type' => 'order_note'
|
448 |
-
);
|
449 |
-
|
450 |
-
remove_filter('comments_clauses', array('WC_Comments', 'exclude_order_comments'), 10, 1);
|
451 |
-
|
452 |
-
$notes = get_comments($args);
|
453 |
-
|
454 |
-
add_filter('comments_clauses', array('WC_Comments', 'exclude_order_comments'), 10, 1);
|
455 |
-
|
456 |
-
$order_notes = array();
|
457 |
-
|
458 |
-
foreach ($notes as $note) {
|
459 |
-
|
460 |
-
$order_notes[] = array(
|
461 |
-
'id' => $note->comment_ID,
|
462 |
-
'created_at' => $this->server->format_datetime($note->comment_date_gmt),
|
463 |
-
'note' => $note->comment_content,
|
464 |
-
'customer_note' => get_comment_meta($note->comment_ID, 'is_customer_note', true) ? true : false,
|
465 |
-
);
|
466 |
-
}
|
467 |
-
|
468 |
-
return array('order_notes' => apply_filters('aftership_api_order_notes_response', $order_notes, $id, $fields, $notes, $this->server));
|
469 |
-
}
|
470 |
-
|
471 |
-
/**
|
472 |
-
* Helper method to get order post objects
|
473 |
-
*
|
474 |
-
* @since 2.1
|
475 |
-
* @param array $args request arguments for filtering query
|
476 |
-
* @return WP_Query
|
477 |
-
*/
|
478 |
-
private function query_orders($args)
|
479 |
-
{
|
480 |
-
|
481 |
-
function aftership_wpbo_get_woo_version_number()
|
482 |
-
{
|
483 |
-
// If get_plugins() isn't available, require it
|
484 |
-
if (!function_exists('get_plugins'))
|
485 |
-
require_once(ABSPATH . 'wp-admin/includes/plugin.php');
|
486 |
-
|
487 |
-
// Create the plugins folder and file variables
|
488 |
-
$plugin_folder = get_plugins('/' . 'woocommerce');
|
489 |
-
$plugin_file = 'woocommerce.php';
|
490 |
-
|
491 |
-
// If the plugin version number is set, return it
|
492 |
-
if (isset($plugin_folder[$plugin_file]['Version'])) {
|
493 |
-
return $plugin_folder[$plugin_file]['Version'];
|
494 |
-
|
495 |
-
} else {
|
496 |
-
// Otherwise return null
|
497 |
-
return NULL;
|
498 |
-
}
|
499 |
-
}
|
500 |
-
|
501 |
-
$woo_version = aftership_wpbo_get_woo_version_number();
|
502 |
-
|
503 |
-
if ($woo_version >= 2.2) {
|
504 |
-
// set base query arguments
|
505 |
-
$query_args = array(
|
506 |
-
'fields' => 'ids',
|
507 |
-
'post_type' => 'shop_order',
|
508 |
-
// 'post_status' => 'publish',
|
509 |
-
'post_status' => array_keys(wc_get_order_statuses())
|
510 |
-
);
|
511 |
-
} else {
|
512 |
-
// set base query arguments
|
513 |
-
$query_args = array(
|
514 |
-
'fields' => 'ids',
|
515 |
-
'post_type' => 'shop_order',
|
516 |
-
'post_status' => 'publish',
|
517 |
-
);
|
518 |
-
}
|
519 |
-
|
520 |
-
// add status argument
|
521 |
-
if (!empty($args['status'])) {
|
522 |
-
|
523 |
-
$statuses = explode(',', $args['status']);
|
524 |
-
|
525 |
-
$query_args['tax_query'] = array(
|
526 |
-
array(
|
527 |
-
'taxonomy' => 'shop_order_status',
|
528 |
-
'field' => 'slug',
|
529 |
-
'terms' => $statuses,
|
530 |
-
),
|
531 |
-
);
|
532 |
-
|
533 |
-
unset($args['status']);
|
534 |
-
}
|
535 |
-
|
536 |
-
$query_args = $this->merge_query_args($query_args, $args);
|
537 |
-
|
538 |
-
return new WP_Query($query_args);
|
539 |
-
}
|
540 |
-
|
541 |
-
/**
|
542 |
-
* Helper method to get the order subtotal
|
543 |
-
*
|
544 |
-
* @since 2.1
|
545 |
-
* @param WC_Order $order
|
546 |
-
* @return float
|
547 |
-
*/
|
548 |
-
private function get_order_subtotal($order)
|
549 |
-
{
|
550 |
-
|
551 |
-
$subtotal = 0;
|
552 |
-
|
553 |
-
// subtotal
|
554 |
-
foreach ($order->get_items() as $item) {
|
555 |
-
|
556 |
-
$subtotal += (isset($item['line_subtotal'])) ? $item['line_subtotal'] : 0;
|
557 |
-
}
|
558 |
-
|
559 |
-
return $subtotal;
|
560 |
-
}
|
561 |
-
|
562 |
-
/**
|
563 |
-
* Get the total number of orders
|
564 |
-
*
|
565 |
-
* @since 2.1
|
566 |
-
* @param string $status
|
567 |
-
* @param array $filter
|
568 |
-
* @return array
|
569 |
-
*/
|
570 |
-
public function ping()
|
571 |
-
{
|
572 |
-
return "pong";
|
573 |
-
}
|
574 |
-
|
575 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
api/class-aftership-api-resource.php
DELETED
@@ -1,416 +0,0 @@
|
|
1 |
-
<?php
|
2 |
-
/**
|
3 |
-
* AfterShip API Resource class
|
4 |
-
*
|
5 |
-
* Provides shared functionality for resource-specific API classes
|
6 |
-
*
|
7 |
-
* @author AfterShip
|
8 |
-
* @category API
|
9 |
-
* @package AfterShip/API
|
10 |
-
* @since 1.0
|
11 |
-
*/
|
12 |
-
|
13 |
-
if (!defined('ABSPATH')) exit; // Exit if accessed directly
|
14 |
-
|
15 |
-
class AfterShip_API_Resource
|
16 |
-
{
|
17 |
-
|
18 |
-
/** @var WC_API_Server the API server */
|
19 |
-
protected $server;
|
20 |
-
|
21 |
-
/** @var string sub-classes override this to set a resource-specific base route */
|
22 |
-
protected $base;
|
23 |
-
|
24 |
-
/**
|
25 |
-
* Setup class
|
26 |
-
*
|
27 |
-
* @since 2.1
|
28 |
-
* @param WC_API_Server $server
|
29 |
-
* @return WC_API_Resource
|
30 |
-
*/
|
31 |
-
public function __construct(AfterShip_API_Server $server)
|
32 |
-
{
|
33 |
-
|
34 |
-
$this->server = $server;
|
35 |
-
|
36 |
-
// automatically register routes for sub-classes
|
37 |
-
add_filter('aftership_api_endpoints', array($this, 'register_routes'));
|
38 |
-
|
39 |
-
// remove fields from responses when requests specify certain fields
|
40 |
-
// note these are hooked at a later priority so data added via filters (e.g. customer data to the order response)
|
41 |
-
// still has the fields filtered properly
|
42 |
-
foreach (array('order', 'coupon', 'customer', 'product', 'report') as $resource) {
|
43 |
-
|
44 |
-
add_filter("aftership_api_{$resource}_response", array($this, 'maybe_add_meta'), 15, 2);
|
45 |
-
add_filter("aftership_api_{$resource}_response", array($this, 'filter_response_fields'), 20, 3);
|
46 |
-
}
|
47 |
-
}
|
48 |
-
|
49 |
-
/**
|
50 |
-
* Validate the request by checking:
|
51 |
-
*
|
52 |
-
* 1) the ID is a valid integer
|
53 |
-
* 2) the ID returns a valid post object and matches the provided post type
|
54 |
-
* 3) the current user has the proper permissions to read/edit/delete the post
|
55 |
-
*
|
56 |
-
* @since 2.1
|
57 |
-
* @param string|int $id the post ID
|
58 |
-
* @param string $type the post type, either `shop_order`, `shop_coupon`, or `product`
|
59 |
-
* @param string $context the context of the request, either `read`, `edit` or `delete`
|
60 |
-
* @return int|WP_Error valid post ID or WP_Error if any of the checks fails
|
61 |
-
*/
|
62 |
-
protected function validate_request($id, $type, $context)
|
63 |
-
{
|
64 |
-
|
65 |
-
if ('shop_order' === $type || 'shop_coupon' === $type)
|
66 |
-
$resource_name = str_replace('shop_', '', $type);
|
67 |
-
else
|
68 |
-
$resource_name = $type;
|
69 |
-
|
70 |
-
$id = absint($id);
|
71 |
-
|
72 |
-
// validate ID
|
73 |
-
if (empty($id))
|
74 |
-
return new WP_Error("aftership_api_invalid_{$resource_name}_id", sprintf(__('Invalid %s ID', 'aftership'), $type), array('status' => 404));
|
75 |
-
|
76 |
-
// only custom post types have per-post type/permission checks
|
77 |
-
if ('customer' !== $type) {
|
78 |
-
|
79 |
-
$post = get_post($id);
|
80 |
-
|
81 |
-
// for checking permissions, product variations are the same as the product post type
|
82 |
-
$post_type = ('product_variation' === $post->post_type) ? 'product' : $post->post_type;
|
83 |
-
|
84 |
-
// validate post type
|
85 |
-
if ($type !== $post_type)
|
86 |
-
return new WP_Error("aftership_api_invalid_{$resource_name}", sprintf(__('Invalid %s', 'aftership'), $resource_name), array('status' => 404));
|
87 |
-
|
88 |
-
// validate permissions
|
89 |
-
switch ($context) {
|
90 |
-
|
91 |
-
case 'read':
|
92 |
-
if (!$this->is_readable($post))
|
93 |
-
return new WP_Error("aftership_api_user_cannot_read_{$resource_name}", sprintf(__('You do not have permission to read this %s', 'aftership'), $resource_name), array('status' => 401));
|
94 |
-
break;
|
95 |
-
|
96 |
-
case 'edit':
|
97 |
-
if (!$this->is_editable($post))
|
98 |
-
return new WP_Error("aftership_api_user_cannot_edit_{$resource_name}", sprintf(__('You do not have permission to edit this %s', 'aftership'), $resource_name), array('status' => 401));
|
99 |
-
break;
|
100 |
-
|
101 |
-
case 'delete':
|
102 |
-
if (!$this->is_deletable($post))
|
103 |
-
return new WP_Error("aftership_api_user_cannot_delete_{$resource_name}", sprintf(__('You do not have permission to delete this %s', 'aftership'), $resource_name), array('status' => 401));
|
104 |
-
break;
|
105 |
-
}
|
106 |
-
}
|
107 |
-
|
108 |
-
return $id;
|
109 |
-
}
|
110 |
-
|
111 |
-
/**
|
112 |
-
* Add common request arguments to argument list before WP_Query is run
|
113 |
-
*
|
114 |
-
* @since 2.1
|
115 |
-
* @param array $base_args required arguments for the query (e.g. `post_type`, etc)
|
116 |
-
* @param array $request_args arguments provided in the request
|
117 |
-
* @return array
|
118 |
-
*/
|
119 |
-
protected function merge_query_args($base_args, $request_args)
|
120 |
-
{
|
121 |
-
|
122 |
-
$args = array();
|
123 |
-
|
124 |
-
// date
|
125 |
-
if (!empty($request_args['created_at_min']) || !empty($request_args['created_at_max']) || !empty($request_args['updated_at_min']) || !empty($request_args['updated_at_max'])) {
|
126 |
-
|
127 |
-
$args['date_query'] = array();
|
128 |
-
|
129 |
-
// resources created after specified date
|
130 |
-
if (!empty($request_args['created_at_min']))
|
131 |
-
$args['date_query'][] = array('column' => 'post_date_gmt', 'after' => $this->server->parse_datetime($request_args['created_at_min']), 'inclusive' => true);
|
132 |
-
|
133 |
-
// resources created before specified date
|
134 |
-
if (!empty($request_args['created_at_max']))
|
135 |
-
$args['date_query'][] = array('column' => 'post_date_gmt', 'before' => $this->server->parse_datetime($request_args['created_at_max']), 'inclusive' => true);
|
136 |
-
|
137 |
-
// resources updated after specified date
|
138 |
-
if (!empty($request_args['updated_at_min']))
|
139 |
-
$args['date_query'][] = array('column' => 'post_modified_gmt', 'after' => $this->server->parse_datetime($request_args['updated_at_min']), 'inclusive' => true);
|
140 |
-
|
141 |
-
// resources updated before specified date
|
142 |
-
if (!empty($request_args['updated_at_max']))
|
143 |
-
$args['date_query'][] = array('column' => 'post_modified_gmt', 'before' => $this->server->parse_datetime($request_args['updated_at_max']), 'inclusive' => true);
|
144 |
-
}
|
145 |
-
|
146 |
-
// search
|
147 |
-
if (!empty($request_args['q']))
|
148 |
-
$args['s'] = $request_args['q'];
|
149 |
-
|
150 |
-
// resources per response
|
151 |
-
if (!empty($request_args['limit']))
|
152 |
-
$args['posts_per_page'] = $request_args['limit'];
|
153 |
-
|
154 |
-
// resource offset
|
155 |
-
if (!empty($request_args['offset']))
|
156 |
-
$args['offset'] = $request_args['offset'];
|
157 |
-
|
158 |
-
// resource page
|
159 |
-
$args['paged'] = (isset($request_args['page'])) ? absint($request_args['page']) : 1;
|
160 |
-
|
161 |
-
// order
|
162 |
-
if (!empty($request_args['orderby']))
|
163 |
-
$args['orderby'] = $request_args['orderby'];
|
164 |
-
if (!empty($request_args['order']))
|
165 |
-
$args['order'] = $request_args['order'];
|
166 |
-
|
167 |
-
return array_merge($base_args, $args);
|
168 |
-
}
|
169 |
-
|
170 |
-
/**
|
171 |
-
* Add meta to resources when requested by the client. Meta is added as a top-level
|
172 |
-
* `<resource_name>_meta` attribute (e.g. `order_meta`) as a list of key/value pairs
|
173 |
-
*
|
174 |
-
* @since 2.1
|
175 |
-
* @param array $data the resource data
|
176 |
-
* @param object $resource the resource object (e.g WC_Order)
|
177 |
-
* @return mixed
|
178 |
-
*/
|
179 |
-
public function maybe_add_meta($data, $resource)
|
180 |
-
{
|
181 |
-
|
182 |
-
if (isset($this->server->params['GET']['filter']['meta']) && 'true' === $this->server->params['GET']['filter']['meta'] && is_object($resource)) {
|
183 |
-
|
184 |
-
// don't attempt to add meta more than once
|
185 |
-
if (preg_grep('/[a-z]+_meta/', array_keys($data)))
|
186 |
-
return $data;
|
187 |
-
|
188 |
-
// define the top-level property name for the meta
|
189 |
-
switch (get_class($resource)) {
|
190 |
-
|
191 |
-
case 'WC_Order':
|
192 |
-
$meta_name = 'order_meta';
|
193 |
-
break;
|
194 |
-
|
195 |
-
case 'WC_Coupon':
|
196 |
-
$meta_name = 'coupon_meta';
|
197 |
-
break;
|
198 |
-
|
199 |
-
case 'WP_User':
|
200 |
-
$meta_name = 'customer_meta';
|
201 |
-
break;
|
202 |
-
|
203 |
-
default:
|
204 |
-
$meta_name = 'product_meta';
|
205 |
-
break;
|
206 |
-
}
|
207 |
-
|
208 |
-
if (is_a($resource, 'WP_User')) {
|
209 |
-
|
210 |
-
// customer meta
|
211 |
-
$meta = (array)get_user_meta($resource->ID);
|
212 |
-
|
213 |
-
} elseif (is_a($resource, 'WC_Product_Variation')) {
|
214 |
-
|
215 |
-
// product variation meta
|
216 |
-
$meta = (array)get_post_meta($resource->get_variation_id());
|
217 |
-
|
218 |
-
} else {
|
219 |
-
|
220 |
-
// coupon/order/product meta
|
221 |
-
$meta = (array)get_post_meta($resource->id);
|
222 |
-
}
|
223 |
-
|
224 |
-
foreach ($meta as $meta_key => $meta_value) {
|
225 |
-
|
226 |
-
// don't add hidden meta by default
|
227 |
-
if (!is_protected_meta($meta_key)) {
|
228 |
-
$data[$meta_name][$meta_key] = maybe_unserialize($meta_value[0]);
|
229 |
-
}
|
230 |
-
}
|
231 |
-
|
232 |
-
}
|
233 |
-
|
234 |
-
return $data;
|
235 |
-
}
|
236 |
-
|
237 |
-
/**
|
238 |
-
* Restrict the fields included in the response if the request specified certain only certain fields should be returned
|
239 |
-
*
|
240 |
-
* @since 2.1
|
241 |
-
* @param array $data the response data
|
242 |
-
* @param object $resource the object that provided the response data, e.g. WC_Coupon or WC_Order
|
243 |
-
* @param array|string the requested list of fields to include in the response
|
244 |
-
* @return array response data
|
245 |
-
*/
|
246 |
-
public function filter_response_fields($data, $resource, $fields)
|
247 |
-
{
|
248 |
-
|
249 |
-
if (!is_array($data) || empty($fields))
|
250 |
-
return $data;
|
251 |
-
|
252 |
-
$fields = explode(',', $fields);
|
253 |
-
$sub_fields = array();
|
254 |
-
|
255 |
-
// get sub fields
|
256 |
-
foreach ($fields as $field) {
|
257 |
-
|
258 |
-
if (false !== strpos($field, '.')) {
|
259 |
-
|
260 |
-
list($name, $value) = explode('.', $field);
|
261 |
-
|
262 |
-
$sub_fields[$name] = $value;
|
263 |
-
}
|
264 |
-
}
|
265 |
-
|
266 |
-
// iterate through top-level fields
|
267 |
-
foreach ($data as $data_field => $data_value) {
|
268 |
-
|
269 |
-
// if a field has sub-fields and the top-level field has sub-fields to filter
|
270 |
-
if (is_array($data_value) && in_array($data_field, array_keys($sub_fields))) {
|
271 |
-
|
272 |
-
// iterate through each sub-field
|
273 |
-
foreach ($data_value as $sub_field => $sub_field_value) {
|
274 |
-
|
275 |
-
// remove non-matching sub-fields
|
276 |
-
if (!in_array($sub_field, $sub_fields)) {
|
277 |
-
unset($data[$data_field][$sub_field]);
|
278 |
-
}
|
279 |
-
}
|
280 |
-
|
281 |
-
} else {
|
282 |
-
|
283 |
-
// remove non-matching top-level fields
|
284 |
-
if (!in_array($data_field, $fields)) {
|
285 |
-
unset($data[$data_field]);
|
286 |
-
}
|
287 |
-
}
|
288 |
-
}
|
289 |
-
|
290 |
-
return $data;
|
291 |
-
}
|
292 |
-
|
293 |
-
/**
|
294 |
-
* Delete a given resource
|
295 |
-
*
|
296 |
-
* @since 2.1
|
297 |
-
* @param int $id the resource ID
|
298 |
-
* @param string $type the resource post type, or `customer`
|
299 |
-
* @param bool $force true to permanently delete resource, false to move to trash (not supported for `customer`)
|
300 |
-
* @return array|WP_Error
|
301 |
-
*/
|
302 |
-
protected function delete($id, $type, $force = false)
|
303 |
-
{
|
304 |
-
|
305 |
-
if ('shop_order' === $type || 'shop_coupon' === $type)
|
306 |
-
$resource_name = str_replace('shop_', '', $type);
|
307 |
-
else
|
308 |
-
$resource_name = $type;
|
309 |
-
|
310 |
-
if ('customer' === $type) {
|
311 |
-
|
312 |
-
$result = wp_delete_user($id);
|
313 |
-
|
314 |
-
if ($result)
|
315 |
-
return array('message' => __('Permanently deleted customer', 'aftership'));
|
316 |
-
else
|
317 |
-
return new WP_Error('aftership_api_cannot_delete_customer', __('The customer cannot be deleted', 'aftership'), array('status' => 500));
|
318 |
-
|
319 |
-
} else {
|
320 |
-
|
321 |
-
// delete order/coupon/product
|
322 |
-
|
323 |
-
$result = ($force) ? wp_delete_post($id, true) : wp_trash_post($id);
|
324 |
-
|
325 |
-
if (!$result)
|
326 |
-
return new WP_Error("aftership_api_cannot_delete_{$resource_name}", sprintf(__('This %s cannot be deleted', 'aftership'), $resource_name), array('status' => 500));
|
327 |
-
|
328 |
-
if ($force) {
|
329 |
-
return array('message' => sprintf(__('Permanently deleted %s', 'aftership'), $resource_name));
|
330 |
-
|
331 |
-
} else {
|
332 |
-
|
333 |
-
$this->server->send_status('202');
|
334 |
-
|
335 |
-
return array('message' => sprintf(__('Deleted %s', 'aftership'), $resource_name));
|
336 |
-
}
|
337 |
-
}
|
338 |
-
}
|
339 |
-
|
340 |
-
|
341 |
-
/**
|
342 |
-
* Checks if the given post is readable by the current user
|
343 |
-
*
|
344 |
-
* @since 2.1
|
345 |
-
* @see WC_API_Resource::check_permission()
|
346 |
-
* @param WP_Post|int $post
|
347 |
-
* @return bool
|
348 |
-
*/
|
349 |
-
protected function is_readable($post)
|
350 |
-
{
|
351 |
-
|
352 |
-
return $this->check_permission($post, 'read');
|
353 |
-
}
|
354 |
-
|
355 |
-
/**
|
356 |
-
* Checks if the given post is editable by the current user
|
357 |
-
*
|
358 |
-
* @since 2.1
|
359 |
-
* @see WC_API_Resource::check_permission()
|
360 |
-
* @param WP_Post|int $post
|
361 |
-
* @return bool
|
362 |
-
*/
|
363 |
-
protected function is_editable($post)
|
364 |
-
{
|
365 |
-
|
366 |
-
return $this->check_permission($post, 'edit');
|
367 |
-
|
368 |
-
}
|
369 |
-
|
370 |
-
/**
|
371 |
-
* Checks if the given post is deletable by the current user
|
372 |
-
*
|
373 |
-
* @since 2.1
|
374 |
-
* @see WC_API_Resource::check_permission()
|
375 |
-
* @param WP_Post|int $post
|
376 |
-
* @return bool
|
377 |
-
*/
|
378 |
-
protected function is_deletable($post)
|
379 |
-
{
|
380 |
-
|
381 |
-
return $this->check_permission($post, 'delete');
|
382 |
-
}
|
383 |
-
|
384 |
-
/**
|
385 |
-
* Checks the permissions for the current user given a post and context
|
386 |
-
*
|
387 |
-
* @since 2.1
|
388 |
-
* @param WP_Post|int $post
|
389 |
-
* @param string $context the type of permission to check, either `read`, `write`, or `delete`
|
390 |
-
* @return bool true if the current user has the permissions to perform the context on the post
|
391 |
-
*/
|
392 |
-
private function check_permission($post, $context)
|
393 |
-
{
|
394 |
-
|
395 |
-
if (!is_a($post, 'WP_Post'))
|
396 |
-
$post = get_post($post);
|
397 |
-
|
398 |
-
if (is_null($post))
|
399 |
-
return false;
|
400 |
-
|
401 |
-
$post_type = get_post_type_object($post->post_type);
|
402 |
-
|
403 |
-
if ('read' === $context)
|
404 |
-
return current_user_can($post_type->cap->read_private_posts, $post->ID);
|
405 |
-
|
406 |
-
elseif ('edit' === $context)
|
407 |
-
return current_user_can($post_type->cap->edit_post, $post->ID);
|
408 |
-
|
409 |
-
elseif ('delete' === $context)
|
410 |
-
return current_user_can($post_type->cap->delete_post, $post->ID);
|
411 |
-
|
412 |
-
else
|
413 |
-
return false;
|
414 |
-
}
|
415 |
-
|
416 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
api/class-aftership-api-server.php
DELETED
@@ -1,1031 +0,0 @@
|
|
1 |
-
<?php
|
2 |
-
/**
|
3 |
-
* AfterShip API
|
4 |
-
*
|
5 |
-
* Handles REST API requests
|
6 |
-
*
|
7 |
-
* This class and related code (JSON response handler, resource classes) are based on WP-API v0.6 (https://github.com/WP-API/WP-API)
|
8 |
-
* Many thanks to Ryan McCue and any other contributors!
|
9 |
-
*
|
10 |
-
* @author AfterShip
|
11 |
-
* @category API
|
12 |
-
* @package AfterShip/API
|
13 |
-
* @since 1.0
|
14 |
-
*/
|
15 |
-
|
16 |
-
if (!defined('ABSPATH')) exit; // Exit if accessed directly
|
17 |
-
|
18 |
-
require_once ABSPATH . 'wp-admin/includes/admin.php';
|
19 |
-
|
20 |
-
class AfterShip_API_Server
|
21 |
-
{
|
22 |
-
|
23 |
-
const METHOD_GET = 1;
|
24 |
-
const METHOD_POST = 2;
|
25 |
-
const METHOD_PUT = 4;
|
26 |
-
const METHOD_PATCH = 8;
|
27 |
-
const METHOD_DELETE = 16;
|
28 |
-
|
29 |
-
const READABLE = 1; // GET
|
30 |
-
const CREATABLE = 2; // POST
|
31 |
-
const EDITABLE = 14; // POST | PUT | PATCH
|
32 |
-
const DELETABLE = 16; // DELETE
|
33 |
-
const ALLMETHODS = 31; // GET | POST | PUT | PATCH | DELETE
|
34 |
-
|
35 |
-
/**
|
36 |
-
* Does the endpoint accept a raw request body?
|
37 |
-
*/
|
38 |
-
const ACCEPT_RAW_DATA = 64;
|
39 |
-
|
40 |
-
/** Does the endpoint accept a request body? (either JSON or XML) */
|
41 |
-
const ACCEPT_DATA = 128;
|
42 |
-
|
43 |
-
/**
|
44 |
-
* Should we hide this endpoint from the index?
|
45 |
-
*/
|
46 |
-
const HIDDEN_ENDPOINT = 256;
|
47 |
-
|
48 |
-
/**
|
49 |
-
* Map of HTTP verbs to constants
|
50 |
-
* @var array
|
51 |
-
*/
|
52 |
-
public static $method_map = array(
|
53 |
-
'HEAD' => self::METHOD_GET,
|
54 |
-
'GET' => self::METHOD_GET,
|
55 |
-
'POST' => self::METHOD_POST,
|
56 |
-
'PUT' => self::METHOD_PUT,
|
57 |
-
'PATCH' => self::METHOD_PATCH,
|
58 |
-
'DELETE' => self::METHOD_DELETE,
|
59 |
-
);
|
60 |
-
|
61 |
-
/**
|
62 |
-
* Requested path (relative to the API root, wp-json.php)
|
63 |
-
*
|
64 |
-
* @var string
|
65 |
-
*/
|
66 |
-
public $path = '';
|
67 |
-
|
68 |
-
/**
|
69 |
-
* Requested method (GET/HEAD/POST/PUT/PATCH/DELETE)
|
70 |
-
*
|
71 |
-
* @var string
|
72 |
-
*/
|
73 |
-
public $method = 'HEAD';
|
74 |
-
|
75 |
-
/**
|
76 |
-
* Request parameters
|
77 |
-
*
|
78 |
-
* This acts as an abstraction of the superglobals
|
79 |
-
* (GET => $_GET, POST => $_POST)
|
80 |
-
*
|
81 |
-
* @var array
|
82 |
-
*/
|
83 |
-
public $params = array('GET' => array(), 'POST' => array());
|
84 |
-
|
85 |
-
/**
|
86 |
-
* Request headers
|
87 |
-
*
|
88 |
-
* @var array
|
89 |
-
*/
|
90 |
-
public $headers = array();
|
91 |
-
|
92 |
-
/**
|
93 |
-
* Request files (matches $_FILES)
|
94 |
-
*
|
95 |
-
* @var array
|
96 |
-
*/
|
97 |
-
public $files = array();
|
98 |
-
|
99 |
-
/**
|
100 |
-
* Request/Response handler, either JSON by default
|
101 |
-
* or XML if requested by client
|
102 |
-
*
|
103 |
-
* @var WC_API_Handler
|
104 |
-
*/
|
105 |
-
public $handler;
|
106 |
-
|
107 |
-
|
108 |
-
/**
|
109 |
-
* Setup class and set request/response handler
|
110 |
-
*
|
111 |
-
* @since 2.1
|
112 |
-
* @param $path
|
113 |
-
* @return WC_API_Server
|
114 |
-
*/
|
115 |
-
public function __construct($path)
|
116 |
-
{
|
117 |
-
|
118 |
-
if (empty($path)) {
|
119 |
-
if (isset($_SERVER['PATH_INFO']))
|
120 |
-
$path = $_SERVER['PATH_INFO'];
|
121 |
-
else
|
122 |
-
$path = '/';
|
123 |
-
}
|
124 |
-
|
125 |
-
$this->path = $path;
|
126 |
-
$this->method = $_SERVER['REQUEST_METHOD'];
|
127 |
-
$this->params['GET'] = $_GET;
|
128 |
-
$this->params['POST'] = $_POST;
|
129 |
-
$this->headers = $this->get_headers($_SERVER);
|
130 |
-
$this->files = $_FILES;
|
131 |
-
|
132 |
-
// Compatibility for clients that can't use PUT/PATCH/DELETE
|
133 |
-
if (isset($_GET['_method'])) {
|
134 |
-
$this->method = strtoupper($_GET['_method']);
|
135 |
-
}
|
136 |
-
|
137 |
-
// determine type of request/response and load handler, JSON by default
|
138 |
-
if ($this->is_json_request()){
|
139 |
-
$handler_class = 'AfterShip_API_JSON_Handler';
|
140 |
-
}elseif ($this->is_xml_request()){
|
141 |
-
$handler_class = 'WC_API_XML_Handler';
|
142 |
-
}else{
|
143 |
-
$handler_class = apply_filters('aftership_api_default_response_handler', 'AfterShip_API_JSON_Handler', $this->path, $this);
|
144 |
-
}
|
145 |
-
if (!$this->is_legacy()) {
|
146 |
-
$handler_class = 'AfterShip_API_Common_JSON_Handler';
|
147 |
-
}
|
148 |
-
$this->handler = new $handler_class();
|
149 |
-
}
|
150 |
-
|
151 |
-
public function is_legacy() {
|
152 |
-
// check path
|
153 |
-
if ( false !== stripos( $this->path, '/v3' ) ) {
|
154 |
-
return false;
|
155 |
-
}
|
156 |
-
return true;
|
157 |
-
}
|
158 |
-
|
159 |
-
/**
|
160 |
-
* Check authentication for the request
|
161 |
-
*
|
162 |
-
* @since 2.1
|
163 |
-
* @return WP_User|WP_Error WP_User object indicates successful login, WP_Error indicates unsuccessful login
|
164 |
-
*/
|
165 |
-
public function check_authentication()
|
166 |
-
{
|
167 |
-
|
168 |
-
// allow plugins to remove default authentication or add their own authentication
|
169 |
-
$user = apply_filters('aftership_api_check_authentication', null, $this);
|
170 |
-
|
171 |
-
// API requests run under the context of the authenticated user
|
172 |
-
if (is_a($user, 'WP_User'))
|
173 |
-
wp_set_current_user($user->ID);
|
174 |
-
|
175 |
-
// WP_Errors are handled in serve_request()
|
176 |
-
elseif (!is_wp_error($user))
|
177 |
-
$user = new WP_Error('aftership_api_authentication_error', __('Invalid authentication method', 'aftership'), array('code' => 500));
|
178 |
-
|
179 |
-
return $user;
|
180 |
-
}
|
181 |
-
|
182 |
-
/**
|
183 |
-
* Convert an error to an array
|
184 |
-
*
|
185 |
-
* This iterates over all error codes and messages to change it into a flat
|
186 |
-
* array. This enables simpler client behaviour, as it is represented as a
|
187 |
-
* list in JSON rather than an object/map
|
188 |
-
*
|
189 |
-
* @since 2.1
|
190 |
-
* @param WP_Error $error
|
191 |
-
* @return array List of associative arrays with code and message keys
|
192 |
-
*/
|
193 |
-
protected function error_to_array($error)
|
194 |
-
{
|
195 |
-
$errors = array();
|
196 |
-
foreach ((array)$error->errors as $code => $messages) {
|
197 |
-
foreach ((array)$messages as $message) {
|
198 |
-
$errors[] = array('code' => $code, 'message' => $message);
|
199 |
-
}
|
200 |
-
}
|
201 |
-
return array('errors' => $errors);
|
202 |
-
}
|
203 |
-
|
204 |
-
/**
|
205 |
-
* Handle serving an API request
|
206 |
-
*
|
207 |
-
* Matches the current server URI to a route and runs the first matching
|
208 |
-
* callback then outputs a JSON representation of the returned value.
|
209 |
-
*
|
210 |
-
* @since 2.1
|
211 |
-
* @uses WC_API_Server::dispatch()
|
212 |
-
*/
|
213 |
-
public function serve_request()
|
214 |
-
{
|
215 |
-
|
216 |
-
do_action('aftership_api_server_before_serve', $this);
|
217 |
-
|
218 |
-
$this->header('Content-Type', $this->handler->get_content_type(), true);
|
219 |
-
|
220 |
-
// the API is enabled by default
|
221 |
-
if (!apply_filters('aftership_api_enabled', true, $this) || ('no' === get_option('aftership_api_enabled'))) {
|
222 |
-
|
223 |
-
$this->send_status(404);
|
224 |
-
|
225 |
-
echo $this->handler->generate_response(array('errors' => array('code' => 'aftership_api_disabled', 'message' => 'The WooCommerce API is disabled on this site')));
|
226 |
-
|
227 |
-
return;
|
228 |
-
}
|
229 |
-
|
230 |
-
$result = $this->check_authentication();
|
231 |
-
|
232 |
-
// if authorization check was successful, dispatch the request
|
233 |
-
if (!is_wp_error($result)) {
|
234 |
-
$result = $this->dispatch();
|
235 |
-
}
|
236 |
-
|
237 |
-
// handle any dispatch errors
|
238 |
-
if (is_wp_error($result)) {
|
239 |
-
$data = $result->get_error_data();
|
240 |
-
if (is_array($data) && isset($data['status'])) {
|
241 |
-
$this->send_status($data['status']);
|
242 |
-
}
|
243 |
-
|
244 |
-
$result = $this->error_to_array($result);
|
245 |
-
}
|
246 |
-
|
247 |
-
// This is a filter rather than an action, since this is designed to be
|
248 |
-
// re-entrant if needed
|
249 |
-
$served = apply_filters('aftership_api_serve_request', false, $result, $this);
|
250 |
-
|
251 |
-
if (!$served) {
|
252 |
-
|
253 |
-
if ('HEAD' === $this->method)
|
254 |
-
return;
|
255 |
-
|
256 |
-
echo $this->handler->generate_response($result);
|
257 |
-
}
|
258 |
-
}
|
259 |
-
|
260 |
-
/**
|
261 |
-
* Retrieve the route map
|
262 |
-
*
|
263 |
-
* The route map is an associative array with path regexes as the keys. The
|
264 |
-
* value is an indexed array with the callback function/method as the first
|
265 |
-
* item, and a bitmask of HTTP methods as the second item (see the class
|
266 |
-
* constants).
|
267 |
-
*
|
268 |
-
* Each route can be mapped to more than one callback by using an array of
|
269 |
-
* the indexed arrays. This allows mapping e.g. GET requests to one callback
|
270 |
-
* and POST requests to another.
|
271 |
-
*
|
272 |
-
* Note that the path regexes (array keys) must have @ escaped, as this is
|
273 |
-
* used as the delimiter with preg_match()
|
274 |
-
*
|
275 |
-
* @since 2.1
|
276 |
-
* @return array `'/path/regex' => array( $callback, $bitmask )` or `'/path/regex' => array( array( $callback, $bitmask ), ...)`
|
277 |
-
*/
|
278 |
-
public function get_routes()
|
279 |
-
{
|
280 |
-
|
281 |
-
// index added by default
|
282 |
-
$endpoints = array(
|
283 |
-
|
284 |
-
'/' => array(array($this, 'get_index'), self::READABLE),
|
285 |
-
);
|
286 |
-
|
287 |
-
$endpoints = apply_filters('aftership_api_endpoints', $endpoints);
|
288 |
-
|
289 |
-
// Normalise the endpoints
|
290 |
-
foreach ($endpoints as $route => &$handlers) {
|
291 |
-
if (count($handlers) <= 2 && isset($handlers[1]) && !is_array($handlers[1])) {
|
292 |
-
$handlers = array($handlers);
|
293 |
-
}
|
294 |
-
}
|
295 |
-
|
296 |
-
return $endpoints;
|
297 |
-
}
|
298 |
-
|
299 |
-
/**
|
300 |
-
* Match the request to a callback and call it
|
301 |
-
*
|
302 |
-
* @since 2.1
|
303 |
-
* @return mixed The value returned by the callback, or a WP_Error instance
|
304 |
-
*/
|
305 |
-
public function dispatch()
|
306 |
-
{
|
307 |
-
|
308 |
-
switch ($this->method) {
|
309 |
-
|
310 |
-
case 'HEAD':
|
311 |
-
case 'GET':
|
312 |
-
$method = self::METHOD_GET;
|
313 |
-
break;
|
314 |
-
/*
|
315 |
-
case 'POST':
|
316 |
-
$method = self::METHOD_POST;
|
317 |
-
break;
|
318 |
-
|
319 |
-
case 'PUT':
|
320 |
-
$method = self::METHOD_PUT;
|
321 |
-
break;
|
322 |
-
|
323 |
-
case 'PATCH':
|
324 |
-
$method = self::METHOD_PATCH;
|
325 |
-
break;
|
326 |
-
|
327 |
-
case 'DELETE':
|
328 |
-
$method = self::METHOD_DELETE;
|
329 |
-
break;
|
330 |
-
*/
|
331 |
-
default:
|
332 |
-
return new WP_Error('aftership_api_unsupported_method', __('Unsupported request method', 'aftership'), array('status' => 400));
|
333 |
-
}
|
334 |
-
|
335 |
-
foreach ($this->get_routes() as $route => $handlers) {
|
336 |
-
foreach ($handlers as $handler) {
|
337 |
-
$callback = $handler[0];
|
338 |
-
$supported = isset($handler[1]) ? $handler[1] : self::METHOD_GET;
|
339 |
-
|
340 |
-
if (!($supported & $method))
|
341 |
-
continue;
|
342 |
-
|
343 |
-
$match = preg_match('@^' . $route . '$@i', urldecode($this->path), $args);
|
344 |
-
|
345 |
-
if (!$match)
|
346 |
-
continue;
|
347 |
-
|
348 |
-
if (!is_callable($callback))
|
349 |
-
return new WP_Error('aftership_api_invalid_handler', __('The handler for the route is invalid', 'aftership'), array('status' => 500));
|
350 |
-
|
351 |
-
$args = array_merge($args, $this->params['GET']);
|
352 |
-
if ($method & self::METHOD_POST) {
|
353 |
-
$args = array_merge($args, $this->params['POST']);
|
354 |
-
}
|
355 |
-
if ($supported & self::ACCEPT_DATA) {
|
356 |
-
$data = $this->handler->parse_body($this->get_raw_data());
|
357 |
-
$args = array_merge($args, array('data' => $data));
|
358 |
-
} elseif ($supported & self::ACCEPT_RAW_DATA) {
|
359 |
-
$data = $this->get_raw_data();
|
360 |
-
$args = array_merge($args, array('data' => $data));
|
361 |
-
}
|
362 |
-
|
363 |
-
$args['_method'] = $method;
|
364 |
-
$args['_route'] = $route;
|
365 |
-
$args['_path'] = $this->path;
|
366 |
-
$args['_headers'] = $this->headers;
|
367 |
-
$args['_files'] = $this->files;
|
368 |
-
|
369 |
-
$args = apply_filters('aftership_api_dispatch_args', $args, $callback);
|
370 |
-
|
371 |
-
// Allow plugins to halt the request via this filter
|
372 |
-
if (is_wp_error($args)) {
|
373 |
-
return $args;
|
374 |
-
}
|
375 |
-
|
376 |
-
$params = $this->sort_callback_params($callback, $args);
|
377 |
-
if (is_wp_error($params))
|
378 |
-
return $params;
|
379 |
-
|
380 |
-
return call_user_func_array($callback, $params);
|
381 |
-
}
|
382 |
-
}
|
383 |
-
|
384 |
-
return new WP_Error('aftership_api_no_route', __('No route was found matching the URL and request method', 'aftership'), array('status' => 404));
|
385 |
-
}
|
386 |
-
|
387 |
-
/**
|
388 |
-
* Sort parameters by order specified in method declaration
|
389 |
-
*
|
390 |
-
* Takes a callback and a list of available params, then filters and sorts
|
391 |
-
* by the parameters the method actually needs, using the Reflection API
|
392 |
-
*
|
393 |
-
* @since 2.1
|
394 |
-
* @param callable|array $callback the endpoint callback
|
395 |
-
* @param array $provided the provided request parameters
|
396 |
-
* @return array
|
397 |
-
*/
|
398 |
-
protected function sort_callback_params($callback, $provided)
|
399 |
-
{
|
400 |
-
if (is_array($callback))
|
401 |
-
$ref_func = new ReflectionMethod($callback[0], $callback[1]);
|
402 |
-
else
|
403 |
-
$ref_func = new ReflectionFunction($callback);
|
404 |
-
|
405 |
-
$wanted = $ref_func->getParameters();
|
406 |
-
$ordered_parameters = array();
|
407 |
-
|
408 |
-
foreach ($wanted as $param) {
|
409 |
-
if (isset($provided[$param->getName()])) {
|
410 |
-
// We have this parameters in the list to choose from
|
411 |
-
|
412 |
-
$ordered_parameters[] = is_array($provided[$param->getName()]) ? array_map('urldecode', $provided[$param->getName()]) : urldecode($provided[$param->getName()]);
|
413 |
-
} elseif ($param->isDefaultValueAvailable()) {
|
414 |
-
// We don't have this parameter, but it's optional
|
415 |
-
$ordered_parameters[] = $param->getDefaultValue();
|
416 |
-
} else {
|
417 |
-
// We don't have this parameter and it wasn't optional, abort!
|
418 |
-
return new WP_Error('aftership_api_missing_callback_param', sprintf(__('Missing parameter %s', 'aftership'), $param->getName()), array('status' => 400));
|
419 |
-
}
|
420 |
-
}
|
421 |
-
return $ordered_parameters;
|
422 |
-
}
|
423 |
-
|
424 |
-
/**
|
425 |
-
* Get the site index.
|
426 |
-
*
|
427 |
-
* This endpoint describes the capabilities of the site.
|
428 |
-
*
|
429 |
-
* @since 2.1
|
430 |
-
* @return array Index entity
|
431 |
-
*/
|
432 |
-
public function get_index()
|
433 |
-
{
|
434 |
-
|
435 |
-
// General site data
|
436 |
-
$available = array('store' => array(
|
437 |
-
'name' => get_option('blogname'),
|
438 |
-
'description' => get_option('blogdescription'),
|
439 |
-
'URL' => get_option('siteurl'),
|
440 |
-
'wc_version' => WC()->version,
|
441 |
-
'latest_api_version' => 'v3',
|
442 |
-
'routes' => array(),
|
443 |
-
'meta' => array(
|
444 |
-
'timezone' => wc_timezone_string(),
|
445 |
-
'currency' => get_woocommerce_currency(),
|
446 |
-
'currency_format' => get_woocommerce_currency_symbol(),
|
447 |
-
'tax_included' => ('yes' === get_option('aftership_prices_include_tax')),
|
448 |
-
'weight_unit' => get_option('aftership_weight_unit'),
|
449 |
-
'dimension_unit' => get_option('aftership_dimension_unit'),
|
450 |
-
'ssl_enabled' => ('yes' === get_option('aftership_force_ssl_checkout')),
|
451 |
-
'permalinks_enabled' => ('' !== get_option('permalink_structure')),
|
452 |
-
'links' => array(
|
453 |
-
'help' => 'https://aftership.uservoice.com/knowledgebase',
|
454 |
-
),
|
455 |
-
),
|
456 |
-
));
|
457 |
-
|
458 |
-
// Find the available routes
|
459 |
-
foreach ($this->get_routes() as $route => $callbacks) {
|
460 |
-
$data = array();
|
461 |
-
|
462 |
-
$route = preg_replace('#\(\?P(<\w+?>).*?\)#', '$1', $route);
|
463 |
-
$methods = array();
|
464 |
-
foreach (self::$method_map as $name => $bitmask) {
|
465 |
-
foreach ($callbacks as $callback) {
|
466 |
-
// Skip to the next route if any callback is hidden
|
467 |
-
if ($callback[1] & self::HIDDEN_ENDPOINT)
|
468 |
-
continue 3;
|
469 |
-
|
470 |
-
if ($callback[1] & $bitmask)
|
471 |
-
$data['supports'][] = $name;
|
472 |
-
|
473 |
-
if ($callback[1] & self::ACCEPT_DATA)
|
474 |
-
$data['accepts_data'] = true;
|
475 |
-
|
476 |
-
// For non-variable routes, generate links
|
477 |
-
if (strpos($route, '<') === false) {
|
478 |
-
$data['meta'] = array(
|
479 |
-
'self' => $route,
|
480 |
-
);
|
481 |
-
}
|
482 |
-
}
|
483 |
-
}
|
484 |
-
$available['store']['routes'][$route] = apply_filters('aftership_api_endpoints_description', $data);
|
485 |
-
}
|
486 |
-
return apply_filters('aftership_api_index', $available);
|
487 |
-
}
|
488 |
-
|
489 |
-
/**
|
490 |
-
* Send a HTTP status code
|
491 |
-
*
|
492 |
-
* @since 2.1
|
493 |
-
* @param int $code HTTP status
|
494 |
-
*/
|
495 |
-
public function send_status($code)
|
496 |
-
{
|
497 |
-
status_header($code);
|
498 |
-
}
|
499 |
-
|
500 |
-
/**
|
501 |
-
* Send a HTTP header
|
502 |
-
*
|
503 |
-
* @since 2.1
|
504 |
-
* @param string $key Header key
|
505 |
-
* @param string $value Header value
|
506 |
-
* @param boolean $replace Should we replace the existing header?
|
507 |
-
*/
|
508 |
-
public function header($key, $value, $replace = true)
|
509 |
-
{
|
510 |
-
header(sprintf('%s: %s', $key, $value), $replace);
|
511 |
-
}
|
512 |
-
|
513 |
-
/**
|
514 |
-
* Send a Link header
|
515 |
-
*
|
516 |
-
* @internal The $rel parameter is first, as this looks nicer when sending multiple
|
517 |
-
*
|
518 |
-
* @link http://tools.ietf.org/html/rfc5988
|
519 |
-
* @link http://www.iana.org/assignments/link-relations/link-relations.xml
|
520 |
-
*
|
521 |
-
* @since 2.1
|
522 |
-
* @param string $rel Link relation. Either a registered type, or an absolute URL
|
523 |
-
* @param string $link Target IRI for the link
|
524 |
-
* @param array $other Other parameters to send, as an associative array
|
525 |
-
*/
|
526 |
-
public function link_header($rel, $link, $other = array())
|
527 |
-
{
|
528 |
-
|
529 |
-
$header = sprintf('<%s>; rel="%s"', $link, esc_attr($rel));
|
530 |
-
|
531 |
-
foreach ($other as $key => $value) {
|
532 |
-
|
533 |
-
if ('title' == $key) {
|
534 |
-
|
535 |
-
$value = '"' . $value . '"';
|
536 |
-
}
|
537 |
-
|
538 |
-
$header .= '; ' . $key . '=' . $value;
|
539 |
-
}
|
540 |
-
|
541 |
-
$this->header('Link', $header, false);
|
542 |
-
}
|
543 |
-
|
544 |
-
/**
|
545 |
-
* Send pagination headers for resources
|
546 |
-
*
|
547 |
-
* @since 2.1
|
548 |
-
* @param WP_Query|WP_User_Query $query
|
549 |
-
*/
|
550 |
-
public function add_pagination_headers($query)
|
551 |
-
{
|
552 |
-
|
553 |
-
// WP_User_Query
|
554 |
-
if (is_a($query, 'WP_User_Query')) {
|
555 |
-
|
556 |
-
$page = $query->page;
|
557 |
-
$single = count($query->get_results()) > 1;
|
558 |
-
$total = $query->get_total();
|
559 |
-
$total_pages = $query->total_pages;
|
560 |
-
|
561 |
-
// WP_Query
|
562 |
-
} else {
|
563 |
-
|
564 |
-
$page = $query->get('paged');
|
565 |
-
$single = $query->is_single();
|
566 |
-
$total = $query->found_posts;
|
567 |
-
$total_pages = $query->max_num_pages;
|
568 |
-
}
|
569 |
-
|
570 |
-
if (!$page)
|
571 |
-
$page = 1;
|
572 |
-
|
573 |
-
$next_page = absint($page) + 1;
|
574 |
-
|
575 |
-
if (!$single) {
|
576 |
-
|
577 |
-
// first/prev
|
578 |
-
if ($page > 1) {
|
579 |
-
$this->link_header('first', $this->get_paginated_url(1));
|
580 |
-
$this->link_header('prev', $this->get_paginated_url($page - 1));
|
581 |
-
}
|
582 |
-
|
583 |
-
// next
|
584 |
-
if ($next_page <= $total_pages) {
|
585 |
-
$this->link_header('next', $this->get_paginated_url($next_page));
|
586 |
-
}
|
587 |
-
|
588 |
-
// last
|
589 |
-
if ($page != $total_pages)
|
590 |
-
$this->link_header('last', $this->get_paginated_url($total_pages));
|
591 |
-
}
|
592 |
-
|
593 |
-
$this->header('X-WC-Total', $total);
|
594 |
-
$this->header('X-WC-TotalPages', $total_pages);
|
595 |
-
|
596 |
-
do_action('aftership_api_pagination_headers', $this, $query);
|
597 |
-
}
|
598 |
-
|
599 |
-
/**
|
600 |
-
* Returns the request URL with the page query parameter set to the specified page
|
601 |
-
*
|
602 |
-
* @since 2.1
|
603 |
-
* @param int $page
|
604 |
-
* @return string
|
605 |
-
*/
|
606 |
-
private function get_paginated_url($page)
|
607 |
-
{
|
608 |
-
|
609 |
-
// remove existing page query param
|
610 |
-
$request = remove_query_arg('page');
|
611 |
-
|
612 |
-
// add provided page query param
|
613 |
-
$request = urldecode(add_query_arg('page', $page, $request));
|
614 |
-
|
615 |
-
// get the home host
|
616 |
-
$host = parse_url(get_home_url(), PHP_URL_HOST);
|
617 |
-
|
618 |
-
return set_url_scheme("http://{$host}{$request}");
|
619 |
-
}
|
620 |
-
|
621 |
-
/**
|
622 |
-
* Retrieve the raw request entity (body)
|
623 |
-
*
|
624 |
-
* @since 2.1
|
625 |
-
* @return string
|
626 |
-
*/
|
627 |
-
public function get_raw_data()
|
628 |
-
{
|
629 |
-
return file_get_contents('php://input');
|
630 |
-
}
|
631 |
-
|
632 |
-
/**
|
633 |
-
* Parse an RFC3339 datetime into a MySQl datetime
|
634 |
-
*
|
635 |
-
* Invalid dates default to unix epoch
|
636 |
-
*
|
637 |
-
* @since 2.1
|
638 |
-
* @param string $datetime RFC3339 datetime
|
639 |
-
* @return string MySQl datetime (YYYY-MM-DD HH:MM:SS)
|
640 |
-
*/
|
641 |
-
public function parse_datetime($datetime)
|
642 |
-
{
|
643 |
-
|
644 |
-
// Strip millisecond precision (a full stop followed by one or more digits)
|
645 |
-
if (strpos($datetime, '.') !== false) {
|
646 |
-
$datetime = preg_replace('/\.\d+/', '', $datetime);
|
647 |
-
}
|
648 |
-
|
649 |
-
// default timezone to UTC
|
650 |
-
$datetime = preg_replace('/[+-]\d+:+\d+$/', '+00:00', $datetime);
|
651 |
-
|
652 |
-
try {
|
653 |
-
|
654 |
-
$datetime = new DateTime($datetime, new DateTimeZone('UTC'));
|
655 |
-
|
656 |
-
} catch (Exception $e) {
|
657 |
-
|
658 |
-
$datetime = new DateTime('@0');
|
659 |
-
|
660 |
-
}
|
661 |
-
|
662 |
-
return $datetime->format('Y-m-d H:i:s');
|
663 |
-
}
|
664 |
-
|
665 |
-
/**
|
666 |
-
* Format a unix timestamp or MySQL datetime into an RFC3339 datetime
|
667 |
-
*
|
668 |
-
* @since 2.1
|
669 |
-
* @param int|string $timestamp unix timestamp or MySQL datetime
|
670 |
-
* @param bool $convert_to_utc
|
671 |
-
* @return string RFC3339 datetime
|
672 |
-
*/
|
673 |
-
public function format_datetime($timestamp, $convert_to_utc = false)
|
674 |
-
{
|
675 |
-
|
676 |
-
if ($convert_to_utc) {
|
677 |
-
$timezone = new DateTimeZone(wc_timezone_string());
|
678 |
-
} else {
|
679 |
-
$timezone = new DateTimeZone('UTC');
|
680 |
-
}
|
681 |
-
|
682 |
-
try {
|
683 |
-
|
684 |
-
if (is_numeric($timestamp)) {
|
685 |
-
$date = new DateTime("@{$timestamp}");
|
686 |
-
} else {
|
687 |
-
$date = new DateTime($timestamp, $timezone);
|
688 |
-
}
|
689 |
-
|
690 |
-
// convert to UTC by adjusting the time based on the offset of the site's timezone
|
691 |
-
if ($convert_to_utc) {
|
692 |
-
$date->modify(-1 * $date->getOffset() . ' seconds');
|
693 |
-
}
|
694 |
-
|
695 |
-
} catch (Exception $e) {
|
696 |
-
|
697 |
-
$date = new DateTime('@0');
|
698 |
-
}
|
699 |
-
|
700 |
-
return $date->format('Y-m-d\TH:i:s\Z');
|
701 |
-
}
|
702 |
-
|
703 |
-
/**
|
704 |
-
* Extract headers from a PHP-style $_SERVER array
|
705 |
-
*
|
706 |
-
* @since 2.1
|
707 |
-
* @param array $server Associative array similar to $_SERVER
|
708 |
-
* @return array Headers extracted from the input
|
709 |
-
*/
|
710 |
-
public function get_headers($server)
|
711 |
-
{
|
712 |
-
$headers = array();
|
713 |
-
// CONTENT_* headers are not prefixed with HTTP_
|
714 |
-
$additional = array('CONTENT_LENGTH' => true, 'CONTENT_MD5' => true, 'CONTENT_TYPE' => true);
|
715 |
-
|
716 |
-
foreach ($server as $key => $value) {
|
717 |
-
if (strpos($key, 'HTTP_') === 0) {
|
718 |
-
$headers[substr($key, 5)] = $value;
|
719 |
-
} elseif (isset($additional[$key])) {
|
720 |
-
$headers[$key] = $value;
|
721 |
-
}
|
722 |
-
}
|
723 |
-
|
724 |
-
return $headers;
|
725 |
-
}
|
726 |
-
|
727 |
-
/**
|
728 |
-
* Check if the current request accepts a JSON response by checking the endpoint suffix (.json) or
|
729 |
-
* the HTTP ACCEPT header
|
730 |
-
*
|
731 |
-
* @since 2.1
|
732 |
-
* @return bool
|
733 |
-
*/
|
734 |
-
private function is_json_request()
|
735 |
-
{
|
736 |
-
|
737 |
-
// check path
|
738 |
-
if (false !== stripos($this->path, '.json'))
|
739 |
-
return true;
|
740 |
-
|
741 |
-
// check ACCEPT header, only 'application/json' is acceptable, see RFC 4627
|
742 |
-
if (isset($this->headers['ACCEPT']) && 'application/json' == $this->headers['ACCEPT'])
|
743 |
-
return true;
|
744 |
-
|
745 |
-
return false;
|
746 |
-
}
|
747 |
-
|
748 |
-
/**
|
749 |
-
* Check if the current request accepts an XML response by checking the endpoint suffix (.xml) or
|
750 |
-
* the HTTP ACCEPT header
|
751 |
-
*
|
752 |
-
* @since 2.1
|
753 |
-
* @return bool
|
754 |
-
*/
|
755 |
-
private function is_xml_request()
|
756 |
-
{
|
757 |
-
|
758 |
-
// check path
|
759 |
-
if (false !== stripos($this->path, '.xml'))
|
760 |
-
return true;
|
761 |
-
|
762 |
-
// check headers, 'application/xml' or 'text/xml' are acceptable, see RFC 2376
|
763 |
-
if (isset($this->headers['ACCEPT']) && ('application/xml' == $this->headers['ACCEPT'] || 'text/xml' == $this->headers['ACCEPT']))
|
764 |
-
return true;
|
765 |
-
|
766 |
-
return false;
|
767 |
-
}
|
768 |
-
|
769 |
-
/**
|
770 |
-
* Converts the WooCommerce country codes to 3-letter ISO codes
|
771 |
-
* https://en.wikipedia.org/wiki/ISO_3166-1_alpha-3
|
772 |
-
* @param string WooCommerce's 2 letter country code
|
773 |
-
* @return string ISO 3-letter country code
|
774 |
-
*/
|
775 |
-
public function convert_country_code($country) {
|
776 |
-
$countries = array(
|
777 |
-
'AF' => 'AFG', //Afghanistan
|
778 |
-
'AX' => 'ALA', //Åland Islands
|
779 |
-
'AL' => 'ALB', //Albania
|
780 |
-
'DZ' => 'DZA', //Algeria
|
781 |
-
'AS' => 'ASM', //American Samoa
|
782 |
-
'AD' => 'AND', //Andorra
|
783 |
-
'AO' => 'AGO', //Angola
|
784 |
-
'AI' => 'AIA', //Anguilla
|
785 |
-
'AQ' => 'ATA', //Antarctica
|
786 |
-
'AG' => 'ATG', //Antigua and Barbuda
|
787 |
-
'AR' => 'ARG', //Argentina
|
788 |
-
'AM' => 'ARM', //Armenia
|
789 |
-
'AW' => 'ABW', //Aruba
|
790 |
-
'AU' => 'AUS', //Australia
|
791 |
-
'AT' => 'AUT', //Austria
|
792 |
-
'AZ' => 'AZE', //Azerbaijan
|
793 |
-
'BS' => 'BHS', //Bahamas
|
794 |
-
'BH' => 'BHR', //Bahrain
|
795 |
-
'BD' => 'BGD', //Bangladesh
|
796 |
-
'BB' => 'BRB', //Barbados
|
797 |
-
'BY' => 'BLR', //Belarus
|
798 |
-
'BE' => 'BEL', //Belgium
|
799 |
-
'BZ' => 'BLZ', //Belize
|
800 |
-
'BJ' => 'BEN', //Benin
|
801 |
-
'BM' => 'BMU', //Bermuda
|
802 |
-
'BT' => 'BTN', //Bhutan
|
803 |
-
'BO' => 'BOL', //Bolivia
|
804 |
-
'BQ' => 'BES', //Bonaire, Saint Estatius and Saba
|
805 |
-
'BA' => 'BIH', //Bosnia and Herzegovina
|
806 |
-
'BW' => 'BWA', //Botswana
|
807 |
-
'BV' => 'BVT', //Bouvet Islands
|
808 |
-
'BR' => 'BRA', //Brazil
|
809 |
-
'IO' => 'IOT', //British Indian Ocean Territory
|
810 |
-
'BN' => 'BRN', //Brunei
|
811 |
-
'BG' => 'BGR', //Bulgaria
|
812 |
-
'BF' => 'BFA', //Burkina Faso
|
813 |
-
'BI' => 'BDI', //Burundi
|
814 |
-
'KH' => 'KHM', //Cambodia
|
815 |
-
'CM' => 'CMR', //Cameroon
|
816 |
-
'CA' => 'CAN', //Canada
|
817 |
-
'CV' => 'CPV', //Cape Verde
|
818 |
-
'KY' => 'CYM', //Cayman Islands
|
819 |
-
'CF' => 'CAF', //Central African Republic
|
820 |
-
'TD' => 'TCD', //Chad
|
821 |
-
'CL' => 'CHL', //Chile
|
822 |
-
'CN' => 'CHN', //China
|
823 |
-
'CX' => 'CXR', //Christmas Island
|
824 |
-
'CC' => 'CCK', //Cocos (Keeling) Islands
|
825 |
-
'CO' => 'COL', //Colombia
|
826 |
-
'KM' => 'COM', //Comoros
|
827 |
-
'CG' => 'COG', //Congo
|
828 |
-
'CD' => 'COD', //Congo, Democratic Republic of the
|
829 |
-
'CK' => 'COK', //Cook Islands
|
830 |
-
'CR' => 'CRI', //Costa Rica
|
831 |
-
'CI' => 'CIV', //Côte d\'Ivoire
|
832 |
-
'HR' => 'HRV', //Croatia
|
833 |
-
'CU' => 'CUB', //Cuba
|
834 |
-
'CW' => 'CUW', //Curaçao
|
835 |
-
'CY' => 'CYP', //Cyprus
|
836 |
-
'CZ' => 'CZE', //Czech Republic
|
837 |
-
'DK' => 'DNK', //Denmark
|
838 |
-
'DJ' => 'DJI', //Djibouti
|
839 |
-
'DM' => 'DMA', //Dominica
|
840 |
-
'DO' => 'DOM', //Dominican Republic
|
841 |
-
'EC' => 'ECU', //Ecuador
|
842 |
-
'EG' => 'EGY', //Egypt
|
843 |
-
'SV' => 'SLV', //El Salvador
|
844 |
-
'GQ' => 'GNQ', //Equatorial Guinea
|
845 |
-
'ER' => 'ERI', //Eritrea
|
846 |
-
'EE' => 'EST', //Estonia
|
847 |
-
'ET' => 'ETH', //Ethiopia
|
848 |
-
'FK' => 'FLK', //Falkland Islands
|
849 |
-
'FO' => 'FRO', //Faroe Islands
|
850 |
-
'FJ' => 'FIJ', //Fiji
|
851 |
-
'FI' => 'FIN', //Finland
|
852 |
-
'FR' => 'FRA', //France
|
853 |
-
'GF' => 'GUF', //French Guiana
|
854 |
-
'PF' => 'PYF', //French Polynesia
|
855 |
-
'TF' => 'ATF', //French Southern Territories
|
856 |
-
'GA' => 'GAB', //Gabon
|
857 |
-
'GM' => 'GMB', //Gambia
|
858 |
-
'GE' => 'GEO', //Georgia
|
859 |
-
'DE' => 'DEU', //Germany
|
860 |
-
'GH' => 'GHA', //Ghana
|
861 |
-
'GI' => 'GIB', //Gibraltar
|
862 |
-
'GR' => 'GRC', //Greece
|
863 |
-
'GL' => 'GRL', //Greenland
|
864 |
-
'GD' => 'GRD', //Grenada
|
865 |
-
'GP' => 'GLP', //Guadeloupe
|
866 |
-
'GU' => 'GUM', //Guam
|
867 |
-
'GT' => 'GTM', //Guatemala
|
868 |
-
'GG' => 'GGY', //Guernsey
|
869 |
-
'GN' => 'GIN', //Guinea
|
870 |
-
'GW' => 'GNB', //Guinea-Bissau
|
871 |
-
'GY' => 'GUY', //Guyana
|
872 |
-
'HT' => 'HTI', //Haiti
|
873 |
-
'HM' => 'HMD', //Heard Island and McDonald Islands
|
874 |
-
'VA' => 'VAT', //Holy See (Vatican City State)
|
875 |
-
'HN' => 'HND', //Honduras
|
876 |
-
'HK' => 'HKG', //Hong Kong
|
877 |
-
'HU' => 'HUN', //Hungary
|
878 |
-
'IS' => 'ISL', //Iceland
|
879 |
-
'IN' => 'IND', //India
|
880 |
-
'ID' => 'IDN', //Indonesia
|
881 |
-
'IR' => 'IRN', //Iran
|
882 |
-
'IQ' => 'IRQ', //Iraq
|
883 |
-
'IE' => 'IRL', //Republic of Ireland
|
884 |
-
'IM' => 'IMN', //Isle of Man
|
885 |
-
'IL' => 'ISR', //Israel
|
886 |
-
'IT' => 'ITA', //Italy
|
887 |
-
'JM' => 'JAM', //Jamaica
|
888 |
-
'JP' => 'JPN', //Japan
|
889 |
-
'JE' => 'JEY', //Jersey
|
890 |
-
'JO' => 'JOR', //Jordan
|
891 |
-
'KZ' => 'KAZ', //Kazakhstan
|
892 |
-
'KE' => 'KEN', //Kenya
|
893 |
-
'KI' => 'KIR', //Kiribati
|
894 |
-
'KP' => 'PRK', //Korea, Democratic People\'s Republic of
|
895 |
-
'KR' => 'KOR', //Korea, Republic of (South)
|
896 |
-
'KW' => 'KWT', //Kuwait
|
897 |
-
'KG' => 'KGZ', //Kyrgyzstan
|
898 |
-
'LA' => 'LAO', //Laos
|
899 |
-
'LV' => 'LVA', //Latvia
|
900 |
-
'LB' => 'LBN', //Lebanon
|
901 |
-
'LS' => 'LSO', //Lesotho
|
902 |
-
'LR' => 'LBR', //Liberia
|
903 |
-
'LY' => 'LBY', //Libya
|
904 |
-
'LI' => 'LIE', //Liechtenstein
|
905 |
-
'LT' => 'LTU', //Lithuania
|
906 |
-
'LU' => 'LUX', //Luxembourg
|
907 |
-
'MO' => 'MAC', //Macao S.A.R., China
|
908 |
-
'MK' => 'MKD', //Macedonia
|
909 |
-
'MG' => 'MDG', //Madagascar
|
910 |
-
'MW' => 'MWI', //Malawi
|
911 |
-
'MY' => 'MYS', //Malaysia
|
912 |
-
'MV' => 'MDV', //Maldives
|
913 |
-
'ML' => 'MLI', //Mali
|
914 |
-
'MT' => 'MLT', //Malta
|
915 |
-
'MH' => 'MHL', //Marshall Islands
|
916 |
-
'MQ' => 'MTQ', //Martinique
|
917 |
-
'MR' => 'MRT', //Mauritania
|
918 |
-
'MU' => 'MUS', //Mauritius
|
919 |
-
'YT' => 'MYT', //Mayotte
|
920 |
-
'MX' => 'MEX', //Mexico
|
921 |
-
'FM' => 'FSM', //Micronesia
|
922 |
-
'MD' => 'MDA', //Moldova
|
923 |
-
'MC' => 'MCO', //Monaco
|
924 |
-
'MN' => 'MNG', //Mongolia
|
925 |
-
'ME' => 'MNE', //Montenegro
|
926 |
-
'MS' => 'MSR', //Montserrat
|
927 |
-
'MA' => 'MAR', //Morocco
|
928 |
-
'MZ' => 'MOZ', //Mozambique
|
929 |
-
'MM' => 'MMR', //Myanmar
|
930 |
-
'NA' => 'NAM', //Namibia
|
931 |
-
'NR' => 'NRU', //Nauru
|
932 |
-
'NP' => 'NPL', //Nepal
|
933 |
-
'NL' => 'NLD', //Netherlands
|
934 |
-
'AN' => 'ANT', //Netherlands Antilles
|
935 |
-
'NC' => 'NCL', //New Caledonia
|
936 |
-
'NZ' => 'NZL', //New Zealand
|
937 |
-
'NI' => 'NIC', //Nicaragua
|
938 |
-
'NE' => 'NER', //Niger
|
939 |
-
'NG' => 'NGA', //Nigeria
|
940 |
-
'NU' => 'NIU', //Niue
|
941 |
-
'NF' => 'NFK', //Norfolk Island
|
942 |
-
'MP' => 'MNP', //Northern Mariana Islands
|
943 |
-
'NO' => 'NOR', //Norway
|
944 |
-
'OM' => 'OMN', //Oman
|
945 |
-
'PK' => 'PAK', //Pakistan
|
946 |
-
'PW' => 'PLW', //Palau
|
947 |
-
'PS' => 'PSE', //Palestinian Territory
|
948 |
-
'PA' => 'PAN', //Panama
|
949 |
-
'PG' => 'PNG', //Papua New Guinea
|
950 |
-
'PY' => 'PRY', //Paraguay
|
951 |
-
'PE' => 'PER', //Peru
|
952 |
-
'PH' => 'PHL', //Philippines
|
953 |
-
'PN' => 'PCN', //Pitcairn
|
954 |
-
'PL' => 'POL', //Poland
|
955 |
-
'PT' => 'PRT', //Portugal
|
956 |
-
'PR' => 'PRI', //Puerto Rico
|
957 |
-
'QA' => 'QAT', //Qatar
|
958 |
-
'RE' => 'REU', //Reunion
|
959 |
-
'RO' => 'ROU', //Romania
|
960 |
-
'RU' => 'RUS', //Russia
|
961 |
-
'RW' => 'RWA', //Rwanda
|
962 |
-
'BL' => 'BLM', //Saint Barthélemy
|
963 |
-
'SH' => 'SHN', //Saint Helena
|
964 |
-
'KN' => 'KNA', //Saint Kitts and Nevis
|
965 |
-
'LC' => 'LCA', //Saint Lucia
|
966 |
-
'MF' => 'MAF', //Saint Martin (French part)
|
967 |
-
'SX' => 'SXM', //Sint Maarten / Saint Matin (Dutch part)
|
968 |
-
'PM' => 'SPM', //Saint Pierre and Miquelon
|
969 |
-
'VC' => 'VCT', //Saint Vincent and the Grenadines
|
970 |
-
'WS' => 'WSM', //Samoa
|
971 |
-
'SM' => 'SMR', //San Marino
|
972 |
-
'ST' => 'STP', //São Tomé and Príncipe
|
973 |
-
'SA' => 'SAU', //Saudi Arabia
|
974 |
-
'SN' => 'SEN', //Senegal
|
975 |
-
'RS' => 'SRB', //Serbia
|
976 |
-
'SC' => 'SYC', //Seychelles
|
977 |
-
'SL' => 'SLE', //Sierra Leone
|
978 |
-
'SG' => 'SGP', //Singapore
|
979 |
-
'SK' => 'SVK', //Slovakia
|
980 |
-
'SI' => 'SVN', //Slovenia
|
981 |
-
'SB' => 'SLB', //Solomon Islands
|
982 |
-
'SO' => 'SOM', //Somalia
|
983 |
-
'ZA' => 'ZAF', //South Africa
|
984 |
-
'GS' => 'SGS', //South Georgia/Sandwich Islands
|
985 |
-
'SS' => 'SSD', //South Sudan
|
986 |
-
'ES' => 'ESP', //Spain
|
987 |
-
'LK' => 'LKA', //Sri Lanka
|
988 |
-
'SD' => 'SDN', //Sudan
|
989 |
-
'SR' => 'SUR', //Suriname
|
990 |
-
'SJ' => 'SJM', //Svalbard and Jan Mayen
|
991 |
-
'SZ' => 'SWZ', //Swaziland
|
992 |
-
'SE' => 'SWE', //Sweden
|
993 |
-
'CH' => 'CHE', //Switzerland
|
994 |
-
'SY' => 'SYR', //Syria
|
995 |
-
'TW' => 'TWN', //Taiwan
|
996 |
-
'TJ' => 'TJK', //Tajikistan
|
997 |
-
'TZ' => 'TZA', //Tanzania
|
998 |
-
'TH' => 'THA', //Thailand
|
999 |
-
'TL' => 'TLS', //Timor-Leste
|
1000 |
-
'TG' => 'TGO', //Togo
|
1001 |
-
'TK' => 'TKL', //Tokelau
|
1002 |
-
'TO' => 'TON', //Tonga
|
1003 |
-
'TT' => 'TTO', //Trinidad and Tobago
|
1004 |
-
'TN' => 'TUN', //Tunisia
|
1005 |
-
'TR' => 'TUR', //Turkey
|
1006 |
-
'TM' => 'TKM', //Turkmenistan
|
1007 |
-
'TC' => 'TCA', //Turks and Caicos Islands
|
1008 |
-
'TV' => 'TUV', //Tuvalu
|
1009 |
-
'UG' => 'UGA', //Uganda
|
1010 |
-
'UA' => 'UKR', //Ukraine
|
1011 |
-
'AE' => 'ARE', //United Arab Emirates
|
1012 |
-
'GB' => 'GBR', //United Kingdom
|
1013 |
-
'US' => 'USA', //United States
|
1014 |
-
'UM' => 'UMI', //United States Minor Outlying Islands
|
1015 |
-
'UY' => 'URY', //Uruguay
|
1016 |
-
'UZ' => 'UZB', //Uzbekistan
|
1017 |
-
'VU' => 'VUT', //Vanuatu
|
1018 |
-
'VE' => 'VEN', //Venezuela
|
1019 |
-
'VN' => 'VNM', //Vietnam
|
1020 |
-
'VG' => 'VGB', //Virgin Islands, British
|
1021 |
-
'VI' => 'VIR', //Virgin Island, U.S.
|
1022 |
-
'WF' => 'WLF', //Wallis and Futuna
|
1023 |
-
'EH' => 'ESH', //Western Sahara
|
1024 |
-
'YE' => 'YEM', //Yemen
|
1025 |
-
'ZM' => 'ZMB', //Zambia
|
1026 |
-
'ZW' => 'ZWE', //Zimbabwe
|
1027 |
-
);
|
1028 |
-
$iso_code = isset($countries[$country]) ? $countries[$country] : $country;
|
1029 |
-
return $iso_code;
|
1030 |
-
}
|
1031 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
api/class-aftership-api-v3-orders.php
DELETED
@@ -1,424 +0,0 @@
|
|
1 |
-
<?php
|
2 |
-
/**
|
3 |
-
* AfterShip API Orders Class
|
4 |
-
*
|
5 |
-
* Handles requests to the /orders endpoint
|
6 |
-
*
|
7 |
-
* @author AfterShip
|
8 |
-
* @category API
|
9 |
-
* @package AfterShip/API
|
10 |
-
* @since 1.0
|
11 |
-
*/
|
12 |
-
|
13 |
-
if (!defined('ABSPATH')) {
|
14 |
-
exit;
|
15 |
-
} // Exit if accessed directly
|
16 |
-
|
17 |
-
class AfterShip_API_V3_Orders extends AfterShip_API_Resource
|
18 |
-
{
|
19 |
-
|
20 |
-
/** @var string $base the route base */
|
21 |
-
protected $base = '/v3/orders';
|
22 |
-
|
23 |
-
/**
|
24 |
-
* Register the routes for this class
|
25 |
-
*
|
26 |
-
* GET /orders
|
27 |
-
*
|
28 |
-
* @param array $routes
|
29 |
-
*
|
30 |
-
* @return array
|
31 |
-
* @since 2.1
|
32 |
-
*
|
33 |
-
*/
|
34 |
-
public function register_routes($routes)
|
35 |
-
{
|
36 |
-
# GET /orders/ping
|
37 |
-
$routes[$this->base . '/ping'] = [
|
38 |
-
[[$this, 'ping'], AfterShip_API_Server::READABLE],
|
39 |
-
];
|
40 |
-
|
41 |
-
# GET /orders
|
42 |
-
$routes[$this->base] = [
|
43 |
-
[[$this, 'get_orders'], AfterShip_API_Server::READABLE]
|
44 |
-
];
|
45 |
-
|
46 |
-
# GET /orders/:id
|
47 |
-
$routes[$this->base . '/(?P<id>[\d]+)'] = [
|
48 |
-
[[$this, 'get_order'], AfterShip_API_Server::READABLE],
|
49 |
-
];
|
50 |
-
|
51 |
-
return $routes;
|
52 |
-
}
|
53 |
-
|
54 |
-
/**
|
55 |
-
* heath checkendpoint for wordpress url validation
|
56 |
-
*
|
57 |
-
* @return string
|
58 |
-
* @since 2.1
|
59 |
-
*/
|
60 |
-
public function ping()
|
61 |
-
{
|
62 |
-
return 'pong';
|
63 |
-
}
|
64 |
-
|
65 |
-
/**
|
66 |
-
* Get orders
|
67 |
-
*
|
68 |
-
* @param string $updated_at_min
|
69 |
-
* @param string $updated_at_max
|
70 |
-
* @param string $max_results_number
|
71 |
-
*
|
72 |
-
* @return array
|
73 |
-
* @throws Exception
|
74 |
-
* @since 2.1
|
75 |
-
*
|
76 |
-
*/
|
77 |
-
public function get_orders($fields = null, $filter = array(), $status = null, $page = 1)
|
78 |
-
{
|
79 |
-
if (!empty($status)) {
|
80 |
-
$filter['status'] = $status;
|
81 |
-
}
|
82 |
-
|
83 |
-
$filter['page'] = $page;
|
84 |
-
|
85 |
-
$query = $this->query_orders($filter);
|
86 |
-
|
87 |
-
//define pagination
|
88 |
-
$pagination = [
|
89 |
-
'page' => $query->query['paged'],
|
90 |
-
'limit' => intval($query->query['posts_per_page']),
|
91 |
-
'total' => intval($query->found_posts)
|
92 |
-
];
|
93 |
-
|
94 |
-
$orders = [];
|
95 |
-
foreach ($query->posts as $order_id) {
|
96 |
-
if (!$this->is_readable($order_id)) {
|
97 |
-
continue;
|
98 |
-
}
|
99 |
-
$orders[] = current($this->get_order($order_id, $fields));
|
100 |
-
}
|
101 |
-
|
102 |
-
return ['orders' => $orders, 'pagination' => $pagination];
|
103 |
-
}
|
104 |
-
|
105 |
-
/**
|
106 |
-
* get single order by id
|
107 |
-
* @param $id
|
108 |
-
* @return array|int|WP_Error
|
109 |
-
* @throws Exception
|
110 |
-
*/
|
111 |
-
public function get_order($id, $fields = null)
|
112 |
-
{
|
113 |
-
$weight_unit = get_option('woocommerce_weight_unit');
|
114 |
-
$dp = wc_get_price_decimals();
|
115 |
-
// ensure order ID is valid & user has permission to read
|
116 |
-
$id = $this->validate_request($id, 'shop_order', 'read');
|
117 |
-
if (is_wp_error($id)) {
|
118 |
-
return $id;
|
119 |
-
}
|
120 |
-
$order = new WC_Order($id);
|
121 |
-
$customer = new WC_Customer($order->get_customer_id());
|
122 |
-
$current_shipping_method = current($order->get_shipping_methods());
|
123 |
-
$shipping_method = null;
|
124 |
-
if($current_shipping_method['method_id'] && $current_shipping_method['name']) {
|
125 |
-
$shipping_method = [
|
126 |
-
'code' => $current_shipping_method['method_id'],
|
127 |
-
'name' => $current_shipping_method['name'],
|
128 |
-
];
|
129 |
-
}
|
130 |
-
$order_data = [
|
131 |
-
'id' => (string)$order->get_id(),
|
132 |
-
'order_number' => (string)$order->get_order_number(),
|
133 |
-
'order_name' => '#' . (string)$order->get_order_number(),
|
134 |
-
'taxes_included' => ($order->get_total_tax() > 0),
|
135 |
-
'shipping_method' => $shipping_method,
|
136 |
-
'order_total' => [
|
137 |
-
'currency' => $order->get_currency(),
|
138 |
-
'amount' => (float)wc_format_decimal($order->get_total(), 2),
|
139 |
-
],
|
140 |
-
'note' => $order->get_customer_note(),
|
141 |
-
'locale' => get_locale(),
|
142 |
-
'metrics' => [
|
143 |
-
'placed_at' => $this->server->format_datetime($order->get_date_created()->getTimestamp()),
|
144 |
-
'updated_at' => $this->server->format_datetime($order->get_date_modified()->getTimestamp()),
|
145 |
-
'fully_shipped_at' => null,
|
146 |
-
'expected_earliest_delivery_at' => null,
|
147 |
-
'expected_last_delivery_at' => null,
|
148 |
-
],
|
149 |
-
'customer' => [
|
150 |
-
'id' => (string)$order->get_customer_id(),
|
151 |
-
'first_name' => $customer->get_first_name(),
|
152 |
-
'last_name' => $customer->get_last_name(),
|
153 |
-
'emails' => ($customer->get_email()) ? [$customer->get_email()] : [],
|
154 |
-
'phones' => ($customer->get_billing_phone()) ? [[
|
155 |
-
'country_code' => null,
|
156 |
-
'number' => $customer->get_billing_phone()
|
157 |
-
]] : [],
|
158 |
-
],
|
159 |
-
'shipping_address' => [
|
160 |
-
'first_name' => $order->get_shipping_first_name(),
|
161 |
-
'last_name' => $order->get_shipping_last_name(),
|
162 |
-
'company' => $order->get_shipping_company(),
|
163 |
-
'address_line_1' => $order->get_shipping_address_1(),
|
164 |
-
'address_line_2' => $order->get_shipping_address_2(),
|
165 |
-
'city' => $order->get_shipping_city(),
|
166 |
-
'state' => $order->get_shipping_state(),
|
167 |
-
'country' => $this->server->convert_country_code($order->get_shipping_country()),
|
168 |
-
'postal_code' => $order->get_shipping_postcode(),
|
169 |
-
'email' => $order->get_billing_email(),
|
170 |
-
'phone' => [
|
171 |
-
'country_code' => null,
|
172 |
-
'number' => $order->get_billing_phone()
|
173 |
-
],
|
174 |
-
'address_type' => null,
|
175 |
-
'tax_number' => null,
|
176 |
-
],
|
177 |
-
'billing_address' => array(
|
178 |
-
'first_name' => $order->get_billing_first_name(),
|
179 |
-
'last_name' => $order->get_billing_last_name(),
|
180 |
-
'company' => $order->get_billing_company(),
|
181 |
-
'address_line_1' => $order->get_billing_address_1(),
|
182 |
-
'address_line_2' => $order->get_billing_address_2(),
|
183 |
-
'city' => $order->get_billing_city(),
|
184 |
-
'state' => $order->get_billing_state(),
|
185 |
-
'postal_code' => $order->get_billing_postcode(),
|
186 |
-
'country' => $this->server->convert_country_code($order->get_billing_country()),
|
187 |
-
'email' => $order->get_billing_email(),
|
188 |
-
'phone' => [
|
189 |
-
'country_code' => null,
|
190 |
-
'number' => $order->get_billing_phone()
|
191 |
-
],
|
192 |
-
'address_type' => null,
|
193 |
-
'tax_number' => null,
|
194 |
-
),
|
195 |
-
'status' => $order->get_status(),
|
196 |
-
'items' => [],
|
197 |
-
'trackings' => []
|
198 |
-
];
|
199 |
-
|
200 |
-
|
201 |
-
// add line items
|
202 |
-
foreach ($order->get_items() as $item_id => $item) {
|
203 |
-
if (is_callable($item, 'get_product')) {
|
204 |
-
$product = $item->get_product();
|
205 |
-
} else {
|
206 |
-
$product = $order->get_product_from_item($item);
|
207 |
-
}
|
208 |
-
|
209 |
-
$product_id = 0;
|
210 |
-
$variation_id = 0;
|
211 |
-
$product_sku = null;
|
212 |
-
$weight = '';
|
213 |
-
$product_image_id = 0;
|
214 |
-
|
215 |
-
// Check if the product exists.
|
216 |
-
if ( is_object( $product ) ) {
|
217 |
-
$product_id = $item->get_product_id();
|
218 |
-
$variation_id = $item->get_variation_id();
|
219 |
-
$product_sku = $product->get_sku();
|
220 |
-
$weight = $product->get_weight();
|
221 |
-
$product_image_id = $product->get_image_id();
|
222 |
-
}
|
223 |
-
$subtotal = wc_format_decimal( $order->get_line_subtotal( $item, false, false ), $dp );
|
224 |
-
$total = wc_format_decimal( $order->get_line_total( $item, false, false ), $dp );
|
225 |
-
// set the response object
|
226 |
-
$terms_tags = get_the_terms($product_id, 'product_tag');
|
227 |
-
$product_tags = [];
|
228 |
-
foreach ($terms_tags as $termsKey => $termsVal) {
|
229 |
-
$product_tags[] = $termsVal->name;
|
230 |
-
}
|
231 |
-
$product_categories = [];
|
232 |
-
|
233 |
-
$categories = get_the_terms($product_id, 'product_cat');
|
234 |
-
foreach ($categories as $categoriesKey => $categoriesVal) {
|
235 |
-
$product_categories[] = $categoriesVal->name;
|
236 |
-
}
|
237 |
-
$order_data['items'][] = [
|
238 |
-
'id' => (string)$item_id,
|
239 |
-
'product_id' => $product_id ? (string)$product_id : null,
|
240 |
-
'variant_id' => $variation_id ? (string)$variation_id : null,
|
241 |
-
'sku' => $product_sku,
|
242 |
-
'title' => $item['name'],
|
243 |
-
'quantity' => (int)$item['qty'],
|
244 |
-
'returnable_quantity' => (int)($item['qty'] - abs($order->get_qty_refunded_for_item($item_id))),
|
245 |
-
'unit_weight' => [
|
246 |
-
'unit' => $weight_unit,
|
247 |
-
'value' => $weight === '' ? null : (float)$weight,
|
248 |
-
],
|
249 |
-
'unit_price' => [
|
250 |
-
'currency' => $order->get_currency(),
|
251 |
-
'amount' => round( floatval($subtotal) / intval($item['qty']), $dp),
|
252 |
-
],
|
253 |
-
'discount' => [
|
254 |
-
'currency' => $order->get_currency(),
|
255 |
-
'amount' => (float)($subtotal - $total),
|
256 |
-
],
|
257 |
-
'image_urls' => $product_image_id && wp_get_attachment_url($product_image_id) ? [wp_get_attachment_url($product_image_id)] : [],
|
258 |
-
'tags' => $product_tags,
|
259 |
-
'categories' => $product_categories,
|
260 |
-
];
|
261 |
-
}
|
262 |
-
|
263 |
-
$trackings = [];
|
264 |
-
//The function definition will be available after installing the aftership plugin.
|
265 |
-
if(function_exists('order_post_meta_getter')) {
|
266 |
-
$aftership_tracking_number = order_post_meta_getter($order, 'aftership_tracking_number');
|
267 |
-
if (!empty($aftership_tracking_number)) {
|
268 |
-
$trackings[] = [
|
269 |
-
'slug' => order_post_meta_getter($order, 'aftership_tracking_provider'),
|
270 |
-
'tracking_number' => $aftership_tracking_number,
|
271 |
-
'additional_fields' => [
|
272 |
-
'account_number' => order_post_meta_getter($order, 'aftership_tracking_account'),
|
273 |
-
'key' => order_post_meta_getter($order, 'aftership_tracking_key'),
|
274 |
-
'postal_code' => order_post_meta_getter($order, 'aftership_tracking_postal'),
|
275 |
-
'ship_date' => order_post_meta_getter($order, 'aftership_tracking_shipdate'),
|
276 |
-
'destination_country' => order_post_meta_getter($order, 'aftership_tracking_destination_country'),
|
277 |
-
'state' => null,
|
278 |
-
'origin_country' => null
|
279 |
-
],
|
280 |
-
];
|
281 |
-
}
|
282 |
-
|
283 |
-
// 兼容 woocommerce 官方的 tracking 插件
|
284 |
-
$woocommerce_tracking_arr = order_post_meta_getter($order, 'wc_shipment_tracking_items');
|
285 |
-
if (empty($aftership_tracking_number) && !empty($woocommerce_tracking_arr)) {
|
286 |
-
foreach ($woocommerce_tracking_arr as $trackingKey => $trackingVal) {
|
287 |
-
$trackingInfo = $this->getTrackingInfoByShipmentTracking($trackingVal);
|
288 |
-
$trackings[] = [
|
289 |
-
'slug' => !empty($trackingInfo) ? $trackingInfo['tracking_provider'] : $trackingVal["tracking_provider"],
|
290 |
-
'tracking_number' => $trackingVal["tracking_number"],
|
291 |
-
'additional_fields' => [
|
292 |
-
'account_number' => null,
|
293 |
-
'key' => null,
|
294 |
-
'postal_code' => !empty($trackingInfo) ? $trackingInfo['tracking_postal_code'] : null,
|
295 |
-
'ship_date' => null,
|
296 |
-
'destination_country' => null,
|
297 |
-
'state' => null,
|
298 |
-
'origin_country' => null
|
299 |
-
],
|
300 |
-
];
|
301 |
-
}
|
302 |
-
}
|
303 |
-
$order_data['trackings'] = $trackings;
|
304 |
-
}
|
305 |
-
|
306 |
-
return array('order' => apply_filters('aftership_api_order_response', $order_data, $order, $fields, $this->server));
|
307 |
-
}
|
308 |
-
|
309 |
-
/**
|
310 |
-
* 从wc ShipmentTracking 插件获取 Postalcode - postnl
|
311 |
-
* @param $tracking_items
|
312 |
-
* @return array
|
313 |
-
*/
|
314 |
-
private function getTrackingInfoByShipmentTracking($tracking_items)
|
315 |
-
{
|
316 |
-
if (!isset($tracking_items['custom_tracking_link'])) {
|
317 |
-
return array();
|
318 |
-
}
|
319 |
-
|
320 |
-
// 获取 postnl Postalcode
|
321 |
-
$urlArr = parse_url(stripslashes($tracking_items['custom_tracking_link']));
|
322 |
-
|
323 |
-
if ($urlArr === false) {
|
324 |
-
return array();
|
325 |
-
}
|
326 |
-
|
327 |
-
if (!isset($urlArr['host'])) {
|
328 |
-
return array();
|
329 |
-
}
|
330 |
-
|
331 |
-
$hostArr = explode(".", $urlArr['host']);
|
332 |
-
$hostArrIndex = count($hostArr) - 2;
|
333 |
-
if (empty($hostArr) || !isset($hostArr[$hostArrIndex])) {
|
334 |
-
return array();
|
335 |
-
}
|
336 |
-
|
337 |
-
if ($hostArr[$hostArrIndex] == 'postnl') {
|
338 |
-
parse_str($urlArr['query'], $queryArr);
|
339 |
-
if (!isset($queryArr['Postalcode'])) {
|
340 |
-
return array();
|
341 |
-
}
|
342 |
-
|
343 |
-
return array(
|
344 |
-
'tracking_provider' => 'postnl',
|
345 |
-
'tracking_postal_code' => str_replace(" ", "", $queryArr['Postalcode']),
|
346 |
-
);
|
347 |
-
}
|
348 |
-
return array();
|
349 |
-
}
|
350 |
-
|
351 |
-
|
352 |
-
/**
|
353 |
-
* Helper method to get order post objects
|
354 |
-
*
|
355 |
-
* @param array $args request arguments for filtering query
|
356 |
-
*
|
357 |
-
* @return WP_Query
|
358 |
-
* @since 2.1
|
359 |
-
*
|
360 |
-
*/
|
361 |
-
private function query_orders($args)
|
362 |
-
{
|
363 |
-
|
364 |
-
function aftership_wpbo_get_woo_version_number()
|
365 |
-
{
|
366 |
-
// If get_plugins() isn't available, require it
|
367 |
-
if (!function_exists('get_plugins'))
|
368 |
-
require_once(ABSPATH . 'wp-admin/includes/plugin.php');
|
369 |
-
|
370 |
-
// Create the plugins folder and file variables
|
371 |
-
$plugin_folder = get_plugins('/' . 'woocommerce');
|
372 |
-
$plugin_file = 'woocommerce.php';
|
373 |
-
|
374 |
-
// If the plugin version number is set, return it
|
375 |
-
if (isset($plugin_folder[$plugin_file]['Version'])) {
|
376 |
-
return $plugin_folder[$plugin_file]['Version'];
|
377 |
-
|
378 |
-
} else {
|
379 |
-
// Otherwise return null
|
380 |
-
return NULL;
|
381 |
-
}
|
382 |
-
}
|
383 |
-
|
384 |
-
$woo_version = aftership_wpbo_get_woo_version_number();
|
385 |
-
|
386 |
-
if ($woo_version >= 2.2) {
|
387 |
-
// set base query arguments
|
388 |
-
$query_args = array(
|
389 |
-
'fields' => 'ids',
|
390 |
-
'post_type' => 'shop_order',
|
391 |
-
// 'post_status' => 'publish',
|
392 |
-
'post_status' => array_keys(wc_get_order_statuses())
|
393 |
-
);
|
394 |
-
} else {
|
395 |
-
// set base query arguments
|
396 |
-
$query_args = array(
|
397 |
-
'fields' => 'ids',
|
398 |
-
'post_type' => 'shop_order',
|
399 |
-
'post_status' => 'publish',
|
400 |
-
);
|
401 |
-
}
|
402 |
-
|
403 |
-
// add status argument
|
404 |
-
if (!empty($args['status'])) {
|
405 |
-
|
406 |
-
$statuses = explode(',', $args['status']);
|
407 |
-
|
408 |
-
$query_args['tax_query'] = array(
|
409 |
-
array(
|
410 |
-
'taxonomy' => 'shop_order_status',
|
411 |
-
'field' => 'slug',
|
412 |
-
'terms' => $statuses,
|
413 |
-
),
|
414 |
-
);
|
415 |
-
|
416 |
-
unset($args['status']);
|
417 |
-
}
|
418 |
-
|
419 |
-
$query_args = $this->merge_query_args($query_args, $args);
|
420 |
-
|
421 |
-
return new WP_Query($query_args);
|
422 |
-
}
|
423 |
-
|
424 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
assets/css/admin.css
CHANGED
@@ -1,15 +1,126 @@
|
|
1 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2 |
display: none;
|
3 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
4 |
|
5 |
-
#
|
6 |
width: 100%;
|
7 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
8 |
|
9 |
-
|
10 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
11 |
}
|
12 |
|
13 |
-
|
14 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
15 |
}
|
1 |
+
#woocommerce-aftership .inside {
|
2 |
+
padding: 0px;
|
3 |
+
margin: 0;
|
4 |
+
}
|
5 |
+
#woocommerce-aftership .button-show-form {
|
6 |
+
width: 100%;
|
7 |
+
text-align: center;
|
8 |
+
border: solid 1px #cccccc;
|
9 |
+
background-color: #f7f7f7;
|
10 |
+
border-radius: 3px;
|
11 |
+
color: #555;
|
12 |
+
font-size: 13px;
|
13 |
+
line-height: 15px;
|
14 |
+
}
|
15 |
+
|
16 |
+
#woocommerce-aftership .button-cancel {
|
17 |
+
border-radius: 3px;
|
18 |
+
border: solid 1px #cccccc;
|
19 |
+
background-color: #f7f7f7;
|
20 |
+
color: #555;
|
21 |
+
font-size: 13px;
|
22 |
+
line-height: 15px;
|
23 |
+
margin-left: 12px;
|
24 |
+
}
|
25 |
+
|
26 |
+
#woocommerce-aftership a.link-to-setting {
|
27 |
+
display: block;
|
28 |
+
margin-top: 4px;
|
29 |
+
font-size: 12px;
|
30 |
+
line-height: 1.67;
|
31 |
+
}
|
32 |
+
|
33 |
+
#woocommerce-aftership #aftership-tracking-form {
|
34 |
+
padding: 12px;
|
35 |
display: none;
|
36 |
}
|
37 |
+
#woocommerce-aftership #aftership-tracking-form p.form-field {
|
38 |
+
margin-top: 0;
|
39 |
+
}
|
40 |
+
#woocommerce-aftership #aftership_tracking_slug {
|
41 |
+
width: 100%;
|
42 |
+
max-width: 100%;
|
43 |
+
}
|
44 |
|
45 |
+
#woocommerce-aftership input {
|
46 |
width: 100%;
|
47 |
}
|
48 |
+
#woocommerce-aftership input:invalid {
|
49 |
+
border-color: #aa0000;
|
50 |
+
color: #aa0000;
|
51 |
+
}
|
52 |
+
#woocommerce-aftership input:invalid~div {
|
53 |
+
float: left;
|
54 |
+
color: #aa0000;
|
55 |
+
}
|
56 |
|
57 |
+
|
58 |
+
#woocommerce-aftership .preview_tracking_link {
|
59 |
+
display: none;
|
60 |
+
margin-bottom: 0;
|
61 |
+
}
|
62 |
+
#woocommerce-aftership .preview_tracking_link a {
|
63 |
+
padding: 0 16px 0 0;
|
64 |
+
background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAAVklEQVQYV2NkIBIwoqtTLJn9H13sfk8qI4ZCkCJ0xTgVoisGK0TWDRKAKQKxYXJwhTAFyIpg7gQpRlGIrBtbQICNR7cGJoasAa4QWRCnQmxWIbsbJA8AqXxEC1jaCvYAAAAASUVORK5CYII=)
|
65 |
+
no-repeat right;
|
66 |
+
}
|
67 |
+
#woocommerce-aftership .meta {
|
68 |
+
font-size: 11px;
|
69 |
+
color: #999;
|
70 |
+
padding: 10px;
|
71 |
+
margin: 0;
|
72 |
+
}
|
73 |
+
#woocommerce-aftership #tracking-items {
|
74 |
+
margin: 0;
|
75 |
+
}
|
76 |
+
#woocommerce-aftership .tracking-content {
|
77 |
+
background: #efefef none repeat scroll 0 0;
|
78 |
+
padding: 10px;
|
79 |
+
position: relative;
|
80 |
+
margin: 0;
|
81 |
+
}
|
82 |
+
#woocommerce-aftership .tracking-content:after {
|
83 |
+
content: "";
|
84 |
+
display: block;
|
85 |
+
position: absolute;
|
86 |
+
bottom: -10px;
|
87 |
+
left: 20px;
|
88 |
+
width: 0;
|
89 |
+
height: 0;
|
90 |
+
border-width: 10px 10px 0 0;
|
91 |
+
border-style: solid;
|
92 |
+
border-color: #efefef transparent;
|
93 |
}
|
94 |
|
95 |
+
/* tracking item */
|
96 |
+
|
97 |
+
#woocommerce-aftership .tracking-item {
|
98 |
+
padding: 16px 12px;
|
99 |
+
border-bottom: 1px solid #eeeeee;
|
100 |
+
}
|
101 |
+
.tracking-item a {
|
102 |
+
text-decoration: none;
|
103 |
+
}
|
104 |
+
#woocommerce-aftership .tracking-item-title {
|
105 |
+
display: flex;
|
106 |
+
align-items: center;
|
107 |
+
justify-content: space-between;
|
108 |
+
font-size: 12px;
|
109 |
+
line-height: normal;
|
110 |
+
color: #5f5f5f;
|
111 |
+
margin-bottom: 8px;
|
112 |
+
}
|
113 |
+
#woocommerce-aftership .tracking-item-title a.delete-tracking {
|
114 |
+
color: #a00;
|
115 |
+
margin-left: 12px;
|
116 |
+
}
|
117 |
+
#woocommerce-aftership .tracking-item-content {
|
118 |
+
background-color: #f6f6f6;
|
119 |
+
padding: 12px;
|
120 |
+
font-size: 14px;
|
121 |
+
line-height: 1.43;
|
122 |
+
word-break: break-all;
|
123 |
+
}
|
124 |
+
#woocommerce-aftership .tracking-item-content:first-child {
|
125 |
+
margin-bottom: 4px;
|
126 |
}
|
assets/js/admin.js
DELETED
@@ -1,123 +0,0 @@
|
|
1 |
-
var aftership_woocommerce_tracking_onload_run = false;
|
2 |
-
|
3 |
-
var aftership_woocommerce_tracking_onload = function () {
|
4 |
-
if (aftership_woocommerce_tracking_onload_run) {
|
5 |
-
return aftership_woocommerce_tracking_onload_run;
|
6 |
-
}
|
7 |
-
aftership_woocommerce_tracking_onload_run = true;
|
8 |
-
|
9 |
-
var fields_id = {
|
10 |
-
'tracking_ship_date': 'aftership_tracking_shipdate',
|
11 |
-
'tracking_postal_code': 'aftership_tracking_postal',
|
12 |
-
'tracking_account_number': 'aftership_tracking_account',
|
13 |
-
'tracking_key': 'aftership_tracking_key',
|
14 |
-
'tracking_destination_country': 'aftership_tracking_destination_country'
|
15 |
-
};
|
16 |
-
|
17 |
-
var providers;
|
18 |
-
|
19 |
-
function hide_input_and_label(id) {
|
20 |
-
jQuery('#' + id).hide();
|
21 |
-
jQuery('label[for=' + id + ']').hide();
|
22 |
-
}
|
23 |
-
|
24 |
-
function show_input_and_label(id) {
|
25 |
-
jQuery('#' + id).show();
|
26 |
-
jQuery('label[for=' + id + ']').show();
|
27 |
-
}
|
28 |
-
|
29 |
-
function set_aftership_tracking_provider() {
|
30 |
-
|
31 |
-
jQuery('#aftership_tracking_provider').change(function () {
|
32 |
-
jQuery.each(fields_id, function (index, item) {
|
33 |
-
hide_input_and_label(item);
|
34 |
-
});
|
35 |
-
|
36 |
-
var slug = jQuery(this).val();
|
37 |
-
if (slug) {
|
38 |
-
var provider = providers[slug];
|
39 |
-
var fields = [];
|
40 |
-
if (jQuery.isArray(provider.required_fields)) {
|
41 |
-
fields = provider.required_fields;
|
42 |
-
} else {
|
43 |
-
fields.push(provider.required_fields);
|
44 |
-
}
|
45 |
-
jQuery.each(fields, function (index, item) {
|
46 |
-
if (fields_id[item]) {
|
47 |
-
show_input_and_label(fields_id[item]);
|
48 |
-
}
|
49 |
-
});
|
50 |
-
jQuery('#aftership_tracking_provider_name').val(provider.name);
|
51 |
-
jQuery('#aftership_tracking_required_fields').val(fields.join());
|
52 |
-
}
|
53 |
-
});
|
54 |
-
}
|
55 |
-
|
56 |
-
|
57 |
-
function fill_meta_box(couriers_selected) {
|
58 |
-
var response = get_couriers();
|
59 |
-
var couriers = [];
|
60 |
-
jQuery.each(response, function (index, courier) {
|
61 |
-
if (couriers_selected.indexOf(courier.slug) != -1) {
|
62 |
-
couriers.push(courier);
|
63 |
-
}
|
64 |
-
});
|
65 |
-
|
66 |
-
var selected_provider = jQuery('#aftership_tracking_provider_hidden').val();
|
67 |
-
var find_selected_provider = couriers_selected.indexOf(selected_provider) != -1;
|
68 |
-
if (!find_selected_provider && selected_provider) {
|
69 |
-
couriers.push({
|
70 |
-
slug: selected_provider,
|
71 |
-
name: jQuery("#aftership_tracking_provider_name").val(),
|
72 |
-
required_fields: jQuery("#aftership_tracking_required_fields").val()
|
73 |
-
});
|
74 |
-
}
|
75 |
-
// console.log(couriers);
|
76 |
-
|
77 |
-
couriers = sort_couriers(couriers);
|
78 |
-
|
79 |
-
jQuery.each(couriers, function (key, courier) {
|
80 |
-
var str = '<option ';
|
81 |
-
if (!find_selected_provider && courier['slug'] == selected_provider) {
|
82 |
-
str += 'style="display:none;" ';
|
83 |
-
}
|
84 |
-
str += 'value="' + courier['slug'] + '" ';
|
85 |
-
if (courier['slug'] == selected_provider) {
|
86 |
-
str += 'selected="selected"';
|
87 |
-
}
|
88 |
-
str += '>' + courier['name'] + '</option>';
|
89 |
-
jQuery('#aftership_tracking_provider').append(str);
|
90 |
-
});
|
91 |
-
// jQuery('#aftership_tracking_provider').val(selected_provider);
|
92 |
-
jQuery('#aftership_tracking_provider').trigger("chosen:updated");
|
93 |
-
jQuery('#aftership_tracking_provider_chosen').css({width: '100%'});
|
94 |
-
|
95 |
-
providers = {};
|
96 |
-
jQuery.each(couriers, function (index, courier) {
|
97 |
-
providers[courier.slug] = courier;
|
98 |
-
});
|
99 |
-
set_aftership_tracking_provider();
|
100 |
-
jQuery('#aftership_tracking_provider').trigger('change');
|
101 |
-
}
|
102 |
-
|
103 |
-
if (jQuery('#aftership_tracking_provider').length > 0) {
|
104 |
-
|
105 |
-
jQuery.each(fields_id, function (index, item) {
|
106 |
-
hide_input_and_label(item);
|
107 |
-
});
|
108 |
-
|
109 |
-
var couriers_selected = jQuery('#aftership_couriers_selected').val();
|
110 |
-
var couriers_selected_arr = (couriers_selected) ? couriers_selected.split(',') : [];
|
111 |
-
fill_meta_box(couriers_selected_arr);
|
112 |
-
}
|
113 |
-
|
114 |
-
if (jQuery('#aftership_tracking_provider_name').length > 0) {
|
115 |
-
jQuery('#aftership_tracking_provider_name').parent().hide();
|
116 |
-
}
|
117 |
-
|
118 |
-
if (jQuery('#aftership_tracking_required_fields').length > 0) {
|
119 |
-
jQuery('#aftership_tracking_required_fields').parent().hide();
|
120 |
-
}
|
121 |
-
|
122 |
-
return aftership_woocommerce_tracking_onload_run;
|
123 |
-
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
assets/js/couriers.js
CHANGED
@@ -1,4 +1,3 @@
|
|
1 |
-
// @notice australia-post-api name change to "Australia Post API" different from AfterShip couriers API
|
2 |
function get_couriers() {
|
3 |
var data = [
|
4 |
{
|
|
|
1 |
function get_couriers() {
|
2 |
var data = [
|
3 |
{
|
assets/js/couriers.json
ADDED
@@ -0,0 +1,4718 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
[
|
2 |
+
{
|
3 |
+
"slug": "007ex",
|
4 |
+
"name": "007EX",
|
5 |
+
"other_name": "",
|
6 |
+
"required_fields": []
|
7 |
+
},
|
8 |
+
{
|
9 |
+
"slug": "17postservice",
|
10 |
+
"name": "17 Post Service",
|
11 |
+
"other_name": "17PostService",
|
12 |
+
"required_fields": []
|
13 |
+
},
|
14 |
+
{
|
15 |
+
"slug": "2ebox",
|
16 |
+
"name": "2ebox",
|
17 |
+
"other_name": "",
|
18 |
+
"required_fields": []
|
19 |
+
},
|
20 |
+
{
|
21 |
+
"slug": "2go",
|
22 |
+
"name": "2GO",
|
23 |
+
"other_name": "Negros Navigation",
|
24 |
+
"required_fields": []
|
25 |
+
},
|
26 |
+
{
|
27 |
+
"slug": "360lion",
|
28 |
+
"name": "360 Lion Express",
|
29 |
+
"other_name": "",
|
30 |
+
"required_fields": []
|
31 |
+
},
|
32 |
+
{
|
33 |
+
"slug": "4-72",
|
34 |
+
"name": "4-72 Entregando",
|
35 |
+
"other_name": "Colombia Postal Service",
|
36 |
+
"required_fields": []
|
37 |
+
},
|
38 |
+
{
|
39 |
+
"slug": "4px",
|
40 |
+
"name": "4PX",
|
41 |
+
"other_name": "递四方",
|
42 |
+
"required_fields": []
|
43 |
+
},
|
44 |
+
{
|
45 |
+
"slug": "800bestex",
|
46 |
+
"name": "Best Express",
|
47 |
+
"other_name": "百世汇通",
|
48 |
+
"required_fields": []
|
49 |
+
},
|
50 |
+
{
|
51 |
+
"slug": "99minutos",
|
52 |
+
"name": "99minutos",
|
53 |
+
"other_name": null,
|
54 |
+
"required_fields": []
|
55 |
+
},
|
56 |
+
{
|
57 |
+
"slug": "aaa-cooper",
|
58 |
+
"name": "AAA Cooper",
|
59 |
+
"other_name": "",
|
60 |
+
"required_fields": []
|
61 |
+
},
|
62 |
+
{
|
63 |
+
"slug": "abcustom",
|
64 |
+
"name": "AB Custom Group",
|
65 |
+
"other_name": "",
|
66 |
+
"required_fields": [
|
67 |
+
"tracking_postal_code"
|
68 |
+
]
|
69 |
+
},
|
70 |
+
{
|
71 |
+
"slug": "abf",
|
72 |
+
"name": "ABF Freight",
|
73 |
+
"other_name": "Arkansas Best Corporation",
|
74 |
+
"required_fields": []
|
75 |
+
},
|
76 |
+
{
|
77 |
+
"slug": "abxexpress-my",
|
78 |
+
"name": "ABX Express",
|
79 |
+
"other_name": "ABX Express (M) Sdn Bhd",
|
80 |
+
"required_fields": []
|
81 |
+
},
|
82 |
+
{
|
83 |
+
"slug": "acommerce",
|
84 |
+
"name": "aCommerce",
|
85 |
+
"other_name": "",
|
86 |
+
"required_fields": []
|
87 |
+
},
|
88 |
+
{
|
89 |
+
"slug": "acscourier",
|
90 |
+
"name": "ACS Courier",
|
91 |
+
"other_name": "Αναζήτηση Καταστημάτων",
|
92 |
+
"required_fields": []
|
93 |
+
},
|
94 |
+
{
|
95 |
+
"slug": "acsworldwide",
|
96 |
+
"name": "ACS Worldwide Express",
|
97 |
+
"other_name": "",
|
98 |
+
"required_fields": []
|
99 |
+
},
|
100 |
+
{
|
101 |
+
"slug": "aderonline",
|
102 |
+
"name": "Ader",
|
103 |
+
"other_name": "",
|
104 |
+
"required_fields": []
|
105 |
+
},
|
106 |
+
{
|
107 |
+
"slug": "adicional",
|
108 |
+
"name": "Adicional Logistics",
|
109 |
+
"other_name": "",
|
110 |
+
"required_fields": []
|
111 |
+
},
|
112 |
+
{
|
113 |
+
"slug": "adsone",
|
114 |
+
"name": "ADSOne",
|
115 |
+
"other_name": "ADSOne Group",
|
116 |
+
"required_fields": []
|
117 |
+
},
|
118 |
+
{
|
119 |
+
"slug": "aduiepyle",
|
120 |
+
"name": "A Duie Pyle",
|
121 |
+
"other_name": "",
|
122 |
+
"required_fields": []
|
123 |
+
},
|
124 |
+
{
|
125 |
+
"slug": "aeroflash",
|
126 |
+
"name": "Mexico AeroFlash",
|
127 |
+
"other_name": "AeroFlash",
|
128 |
+
"required_fields": []
|
129 |
+
},
|
130 |
+
{
|
131 |
+
"slug": "aeronet",
|
132 |
+
"name": "Aeronet",
|
133 |
+
"other_name": "",
|
134 |
+
"required_fields": []
|
135 |
+
},
|
136 |
+
{
|
137 |
+
"slug": "aersure",
|
138 |
+
"name": "Aersure",
|
139 |
+
"other_name": "",
|
140 |
+
"required_fields": []
|
141 |
+
},
|
142 |
+
{
|
143 |
+
"slug": "agility",
|
144 |
+
"name": "Agility",
|
145 |
+
"other_name": null,
|
146 |
+
"required_fields": []
|
147 |
+
},
|
148 |
+
{
|
149 |
+
"slug": "air-canada",
|
150 |
+
"name": "Air Canada",
|
151 |
+
"other_name": null,
|
152 |
+
"required_fields": []
|
153 |
+
},
|
154 |
+
{
|
155 |
+
"slug": "air21",
|
156 |
+
"name": "AIR21",
|
157 |
+
"other_name": "AIR 21 PH",
|
158 |
+
"required_fields": []
|
159 |
+
},
|
160 |
+
{
|
161 |
+
"slug": "airmee-webhook",
|
162 |
+
"name": "Airmee",
|
163 |
+
"other_name": "",
|
164 |
+
"required_fields": []
|
165 |
+
},
|
166 |
+
{
|
167 |
+
"slug": "airpak-express",
|
168 |
+
"name": "Airpak Express",
|
169 |
+
"other_name": "",
|
170 |
+
"required_fields": []
|
171 |
+
},
|
172 |
+
{
|
173 |
+
"slug": "airspeed",
|
174 |
+
"name": "Airspeed International Corporation",
|
175 |
+
"other_name": "Airspeed Philippines",
|
176 |
+
"required_fields": []
|
177 |
+
},
|
178 |
+
{
|
179 |
+
"slug": "alfatrex",
|
180 |
+
"name": "AlfaTrex",
|
181 |
+
"other_name": "",
|
182 |
+
"required_fields": []
|
183 |
+
},
|
184 |
+
{
|
185 |
+
"slug": "allied-express-ftp",
|
186 |
+
"name": "Allied Express (FTP)",
|
187 |
+
"other_name": "",
|
188 |
+
"required_fields": []
|
189 |
+
},
|
190 |
+
{
|
191 |
+
"slug": "alliedexpress",
|
192 |
+
"name": "Allied Express",
|
193 |
+
"other_name": "",
|
194 |
+
"required_fields": [
|
195 |
+
"tracking_postal_code"
|
196 |
+
]
|
197 |
+
},
|
198 |
+
{
|
199 |
+
"slug": "alljoy",
|
200 |
+
"name": "ALLJOY SUPPLY CHAIN CO., LTD",
|
201 |
+
"other_name": "",
|
202 |
+
"required_fields": []
|
203 |
+
},
|
204 |
+
{
|
205 |
+
"slug": "alphafast",
|
206 |
+
"name": "alphaFAST",
|
207 |
+
"other_name": "Alpha",
|
208 |
+
"required_fields": []
|
209 |
+
},
|
210 |
+
{
|
211 |
+
"slug": "always-express",
|
212 |
+
"name": "Always Express",
|
213 |
+
"other_name": "",
|
214 |
+
"required_fields": []
|
215 |
+
},
|
216 |
+
{
|
217 |
+
"slug": "amazon",
|
218 |
+
"name": "Amazon Shipping + Amazon MCF",
|
219 |
+
"other_name": "",
|
220 |
+
"required_fields": []
|
221 |
+
},
|
222 |
+
{
|
223 |
+
"slug": "amazon-fba-swiship",
|
224 |
+
"name": "Amazon FBA Swiship",
|
225 |
+
"other_name": null,
|
226 |
+
"required_fields": []
|
227 |
+
},
|
228 |
+
{
|
229 |
+
"slug": "amazon-fba-us",
|
230 |
+
"name": "Amazon",
|
231 |
+
"other_name": "",
|
232 |
+
"required_fields": [
|
233 |
+
"tracking_key"
|
234 |
+
]
|
235 |
+
},
|
236 |
+
{
|
237 |
+
"slug": "amazon-uk-api",
|
238 |
+
"name": "Amazon Shipping",
|
239 |
+
"other_name": null,
|
240 |
+
"required_fields": []
|
241 |
+
},
|
242 |
+
{
|
243 |
+
"slug": "an-post",
|
244 |
+
"name": "An Post",
|
245 |
+
"other_name": "Ireland Post",
|
246 |
+
"required_fields": []
|
247 |
+
},
|
248 |
+
{
|
249 |
+
"slug": "andreani",
|
250 |
+
"name": "Grupo logistico Andreani",
|
251 |
+
"other_name": null,
|
252 |
+
"required_fields": []
|
253 |
+
},
|
254 |
+
{
|
255 |
+
"slug": "anjun",
|
256 |
+
"name": "Anjun",
|
257 |
+
"other_name": null,
|
258 |
+
"required_fields": []
|
259 |
+
},
|
260 |
+
{
|
261 |
+
"slug": "anserx",
|
262 |
+
"name": "ANSERX",
|
263 |
+
"other_name": null,
|
264 |
+
"required_fields": []
|
265 |
+
},
|
266 |
+
{
|
267 |
+
"slug": "anserx-logistics",
|
268 |
+
"name": "ANSERX Logistics",
|
269 |
+
"other_name": null,
|
270 |
+
"required_fields": []
|
271 |
+
},
|
272 |
+
{
|
273 |
+
"slug": "antron",
|
274 |
+
"name": "Antron Express",
|
275 |
+
"other_name": "",
|
276 |
+
"required_fields": []
|
277 |
+
},
|
278 |
+
{
|
279 |
+
"slug": "ao-courier",
|
280 |
+
"name": "AO Logistics",
|
281 |
+
"other_name": "",
|
282 |
+
"required_fields": []
|
283 |
+
},
|
284 |
+
{
|
285 |
+
"slug": "apc",
|
286 |
+
"name": "APC Postal Logistics",
|
287 |
+
"other_name": "APC-PLI",
|
288 |
+
"required_fields": []
|
289 |
+
},
|
290 |
+
{
|
291 |
+
"slug": "apc-overnight",
|
292 |
+
"name": "APC Overnight",
|
293 |
+
"other_name": "Net Despatch",
|
294 |
+
"required_fields": []
|
295 |
+
},
|
296 |
+
{
|
297 |
+
"slug": "apc-overnight-connum",
|
298 |
+
"name": "APC Overnight Consignment Number",
|
299 |
+
"other_name": "",
|
300 |
+
"required_fields": [
|
301 |
+
"tracking_postal_code"
|
302 |
+
]
|
303 |
+
},
|
304 |
+
{
|
305 |
+
"slug": "apg",
|
306 |
+
"name": "APG eCommerce Solutions Ltd.",
|
307 |
+
"other_name": "",
|
308 |
+
"required_fields": []
|
309 |
+
},
|
310 |
+
{
|
311 |
+
"slug": "aprisaexpress",
|
312 |
+
"name": "Aprisa Express",
|
313 |
+
"other_name": "",
|
314 |
+
"required_fields": []
|
315 |
+
},
|
316 |
+
{
|
317 |
+
"slug": "aquiline",
|
318 |
+
"name": "Aquiline",
|
319 |
+
"other_name": "",
|
320 |
+
"required_fields": []
|
321 |
+
},
|
322 |
+
{
|
323 |
+
"slug": "aramex",
|
324 |
+
"name": "Aramex",
|
325 |
+
"other_name": "ارامكس",
|
326 |
+
"required_fields": []
|
327 |
+
},
|
328 |
+
{
|
329 |
+
"slug": "arco-spedizioni",
|
330 |
+
"name": "Arco Spedizioni SP",
|
331 |
+
"other_name": null,
|
332 |
+
"required_fields": []
|
333 |
+
},
|
334 |
+
{
|
335 |
+
"slug": "ark-logistics",
|
336 |
+
"name": "ARK Logistics",
|
337 |
+
"other_name": null,
|
338 |
+
"required_fields": [
|
339 |
+
"tracking_postal_code"
|
340 |
+
]
|
341 |
+
},
|
342 |
+
{
|
343 |
+
"slug": "arrowxl",
|
344 |
+
"name": "Arrow XL",
|
345 |
+
"other_name": "Yodel XL",
|
346 |
+
"required_fields": [
|
347 |
+
"tracking_postal_code"
|
348 |
+
]
|
349 |
+
},
|
350 |
+
{
|
351 |
+
"slug": "asendia-de",
|
352 |
+
"name": "Asendia Germany",
|
353 |
+
"other_name": "Asendia De",
|
354 |
+
"required_fields": []
|
355 |
+
},
|
356 |
+
{
|
357 |
+
"slug": "asendia-hk",
|
358 |
+
"name": "Asendia HK",
|
359 |
+
"other_name": "",
|
360 |
+
"required_fields": []
|
361 |
+
},
|
362 |
+
{
|
363 |
+
"slug": "asendia-uk",
|
364 |
+
"name": "Asendia UK",
|
365 |
+
"other_name": "Asendia United Kingdom",
|
366 |
+
"required_fields": []
|
367 |
+
},
|
368 |
+
{
|
369 |
+
"slug": "asendia-usa",
|
370 |
+
"name": "Asendia USA",
|
371 |
+
"other_name": "Brokers Worldwide",
|
372 |
+
"required_fields": []
|
373 |
+
},
|
374 |
+
{
|
375 |
+
"slug": "asigna",
|
376 |
+
"name": "ASIGNA",
|
377 |
+
"other_name": null,
|
378 |
+
"required_fields": []
|
379 |
+
},
|
380 |
+
{
|
381 |
+
"slug": "asm",
|
382 |
+
"name": "ASM",
|
383 |
+
"other_name": "Asm-Red",
|
384 |
+
"required_fields": [
|
385 |
+
"tracking_postal_code"
|
386 |
+
]
|
387 |
+
},
|
388 |
+
{
|
389 |
+
"slug": "aupost-china",
|
390 |
+
"name": "AuPost China",
|
391 |
+
"other_name": "澳邮宝",
|
392 |
+
"required_fields": []
|
393 |
+
},
|
394 |
+
{
|
395 |
+
"slug": "australia-post",
|
396 |
+
"name": "Australia Post",
|
397 |
+
"other_name": "AusPost",
|
398 |
+
"required_fields": []
|
399 |
+
},
|
400 |
+
{
|
401 |
+
"slug": "australia-post-api",
|
402 |
+
"name": "Australia Post API",
|
403 |
+
"other_name": "",
|
404 |
+
"required_fields": []
|
405 |
+
},
|
406 |
+
{
|
407 |
+
"slug": "australia-post-sftp",
|
408 |
+
"name": "Australia Post Sftp",
|
409 |
+
"other_name": "AusPostSftp",
|
410 |
+
"required_fields": [
|
411 |
+
"tracking_account_number"
|
412 |
+
]
|
413 |
+
},
|
414 |
+
{
|
415 |
+
"slug": "austrian-post",
|
416 |
+
"name": "Austrian Post (Express)",
|
417 |
+
"other_name": "Österreichische Post AG",
|
418 |
+
"required_fields": []
|
419 |
+
},
|
420 |
+
{
|
421 |
+
"slug": "austrian-post-registered",
|
422 |
+
"name": "Austrian Post (Registered)",
|
423 |
+
"other_name": "Österreichische Post AG",
|
424 |
+
"required_fields": []
|
425 |
+
},
|
426 |
+
{
|
427 |
+
"slug": "averitt",
|
428 |
+
"name": "Averitt Express",
|
429 |
+
"other_name": "",
|
430 |
+
"required_fields": []
|
431 |
+
},
|
432 |
+
{
|
433 |
+
"slug": "b2ceurope",
|
434 |
+
"name": "B2C Europe",
|
435 |
+
"other_name": "trackyourparcel.eu",
|
436 |
+
"required_fields": [
|
437 |
+
"tracking_postal_code",
|
438 |
+
"tracking_destination_country"
|
439 |
+
]
|
440 |
+
},
|
441 |
+
{
|
442 |
+
"slug": "belpost",
|
443 |
+
"name": "Belpost",
|
444 |
+
"other_name": "Belposhta, Белпочта",
|
445 |
+
"required_fields": []
|
446 |
+
},
|
447 |
+
{
|
448 |
+
"slug": "bert-fr",
|
449 |
+
"name": "Bert Transport",
|
450 |
+
"other_name": "",
|
451 |
+
"required_fields": []
|
452 |
+
},
|
453 |
+
{
|
454 |
+
"slug": "bestwayparcel",
|
455 |
+
"name": "Best Way Parcel",
|
456 |
+
"other_name": "",
|
457 |
+
"required_fields": [
|
458 |
+
"tracking_key"
|
459 |
+
]
|
460 |
+
},
|
461 |
+
{
|
462 |
+
"slug": "bgpost",
|
463 |
+
"name": "Bulgarian Posts",
|
464 |
+
"other_name": "Български пощи",
|
465 |
+
"required_fields": []
|
466 |
+
},
|
467 |
+
{
|
468 |
+
"slug": "bh-posta",
|
469 |
+
"name": "JP BH Pošta",
|
470 |
+
"other_name": "Bosnia and Herzegovina Post",
|
471 |
+
"required_fields": []
|
472 |
+
},
|
473 |
+
{
|
474 |
+
"slug": "bh-worldwide",
|
475 |
+
"name": "B&H Worldwide",
|
476 |
+
"other_name": "",
|
477 |
+
"required_fields": []
|
478 |
+
},
|
479 |
+
{
|
480 |
+
"slug": "birdsystem",
|
481 |
+
"name": "BirdSystem",
|
482 |
+
"other_name": "",
|
483 |
+
"required_fields": []
|
484 |
+
},
|
485 |
+
{
|
486 |
+
"slug": "bjshomedelivery-ftp",
|
487 |
+
"name": "BJS Distribution, Storage & Couriers - FTP",
|
488 |
+
"other_name": "",
|
489 |
+
"required_fields": []
|
490 |
+
},
|
491 |
+
{
|
492 |
+
"slug": "bluecare",
|
493 |
+
"name": "Bluecare Express Ltd",
|
494 |
+
"other_name": "",
|
495 |
+
"required_fields": []
|
496 |
+
},
|
497 |
+
{
|
498 |
+
"slug": "bluedart",
|
499 |
+
"name": "Bluedart",
|
500 |
+
"other_name": "Blue Dart Express",
|
501 |
+
"required_fields": []
|
502 |
+
},
|
503 |
+
{
|
504 |
+
"slug": "bluestar",
|
505 |
+
"name": "Blue Star",
|
506 |
+
"other_name": "",
|
507 |
+
"required_fields": [
|
508 |
+
"tracking_postal_code"
|
509 |
+
]
|
510 |
+
},
|
511 |
+
{
|
512 |
+
"slug": "bneed",
|
513 |
+
"name": "Bneed",
|
514 |
+
"other_name": "",
|
515 |
+
"required_fields": []
|
516 |
+
},
|
517 |
+
{
|
518 |
+
"slug": "bond",
|
519 |
+
"name": "Bond",
|
520 |
+
"other_name": "",
|
521 |
+
"required_fields": []
|
522 |
+
},
|
523 |
+
{
|
524 |
+
"slug": "bondscouriers",
|
525 |
+
"name": "Bonds Couriers",
|
526 |
+
"other_name": "",
|
527 |
+
"required_fields": []
|
528 |
+
},
|
529 |
+
{
|
530 |
+
"slug": "borderexpress",
|
531 |
+
"name": "Border Express",
|
532 |
+
"other_name": "",
|
533 |
+
"required_fields": []
|
534 |
+
},
|
535 |
+
{
|
536 |
+
"slug": "box-berry",
|
537 |
+
"name": "Boxberry",
|
538 |
+
"other_name": "",
|
539 |
+
"required_fields": []
|
540 |
+
},
|
541 |
+
{
|
542 |
+
"slug": "boxc",
|
543 |
+
"name": "BoxC",
|
544 |
+
"other_name": "BOXC快遞",
|
545 |
+
"required_fields": []
|
546 |
+
},
|
547 |
+
{
|
548 |
+
"slug": "bpost",
|
549 |
+
"name": "Bpost",
|
550 |
+
"other_name": "Belgian Post, Belgium Post",
|
551 |
+
"required_fields": [
|
552 |
+
"tracking_postal_code"
|
553 |
+
]
|
554 |
+
},
|
555 |
+
{
|
556 |
+
"slug": "bpost-api",
|
557 |
+
"name": "Bpost API",
|
558 |
+
"other_name": null,
|
559 |
+
"required_fields": []
|
560 |
+
},
|
561 |
+
{
|
562 |
+
"slug": "bpost-international",
|
563 |
+
"name": "Bpost international",
|
564 |
+
"other_name": "Landmark Global",
|
565 |
+
"required_fields": []
|
566 |
+
},
|
567 |
+
{
|
568 |
+
"slug": "brazil-correios",
|
569 |
+
"name": "Brazil Correios",
|
570 |
+
"other_name": "Brazilian Post",
|
571 |
+
"required_fields": []
|
572 |
+
},
|
573 |
+
{
|
574 |
+
"slug": "bring",
|
575 |
+
"name": "Bring",
|
576 |
+
"other_name": "",
|
577 |
+
"required_fields": []
|
578 |
+
},
|
579 |
+
{
|
580 |
+
"slug": "brouwer-transport",
|
581 |
+
"name": "Brouwer Transport en Logistiek B.V.",
|
582 |
+
"other_name": null,
|
583 |
+
"required_fields": []
|
584 |
+
},
|
585 |
+
{
|
586 |
+
"slug": "brt-it",
|
587 |
+
"name": "BRT Bartolini",
|
588 |
+
"other_name": "BRT Corriere Espresso, DPD Italy",
|
589 |
+
"required_fields": []
|
590 |
+
},
|
591 |
+
{
|
592 |
+
"slug": "brt-it-parcelid",
|
593 |
+
"name": "BRT Bartolini(Parcel ID)",
|
594 |
+
"other_name": "BRT Corriere Espresso, DPD Italy",
|
595 |
+
"required_fields": []
|
596 |
+
},
|
597 |
+
{
|
598 |
+
"slug": "brt-it-sender-ref",
|
599 |
+
"name": "BRT Bartolini(Sender Reference)",
|
600 |
+
"other_name": "",
|
601 |
+
"required_fields": [
|
602 |
+
"tracking_account_number"
|
603 |
+
]
|
604 |
+
},
|
605 |
+
{
|
606 |
+
"slug": "budbee-webhook",
|
607 |
+
"name": "Budbee",
|
608 |
+
"other_name": "",
|
609 |
+
"required_fields": []
|
610 |
+
},
|
611 |
+
{
|
612 |
+
"slug": "buylogic",
|
613 |
+
"name": "Buylogic",
|
614 |
+
"other_name": "捷买送",
|
615 |
+
"required_fields": []
|
616 |
+
},
|
617 |
+
{
|
618 |
+
"slug": "cae-delivers",
|
619 |
+
"name": "CAE Delivers",
|
620 |
+
"other_name": "",
|
621 |
+
"required_fields": []
|
622 |
+
},
|
623 |
+
{
|
624 |
+
"slug": "cainiao",
|
625 |
+
"name": "AliExpress Standard Shipping",
|
626 |
+
"other_name": "CAINIAO",
|
627 |
+
"required_fields": []
|
628 |
+
},
|
629 |
+
{
|
630 |
+
"slug": "cambodia-post",
|
631 |
+
"name": "Cambodia Post",
|
632 |
+
"other_name": "Cambodia Post",
|
633 |
+
"required_fields": []
|
634 |
+
},
|
635 |
+
{
|
636 |
+
"slug": "canada-post",
|
637 |
+
"name": "Canada Post",
|
638 |
+
"other_name": "Postes Canada",
|
639 |
+
"required_fields": []
|
640 |
+
},
|
641 |
+
{
|
642 |
+
"slug": "canpar",
|
643 |
+
"name": "Canpar Courier",
|
644 |
+
"other_name": "TransForce",
|
645 |
+
"required_fields": []
|
646 |
+
},
|
647 |
+
{
|
648 |
+
"slug": "capital",
|
649 |
+
"name": "Capital Transport",
|
650 |
+
"other_name": "",
|
651 |
+
"required_fields": [
|
652 |
+
"tracking_account_number"
|
653 |
+
]
|
654 |
+
},
|
655 |
+
{
|
656 |
+
"slug": "caribou",
|
657 |
+
"name": "Caribou",
|
658 |
+
"other_name": null,
|
659 |
+
"required_fields": []
|
660 |
+
},
|
661 |
+
{
|
662 |
+
"slug": "carriers",
|
663 |
+
"name": "Carriers",
|
664 |
+
"other_name": "",
|
665 |
+
"required_fields": []
|
666 |
+
},
|
667 |
+
{
|
668 |
+
"slug": "carry-flap",
|
669 |
+
"name": "Carry-Flap Co.,Ltd.",
|
670 |
+
"other_name": "",
|
671 |
+
"required_fields": []
|
672 |
+
},
|
673 |
+
{
|
674 |
+
"slug": "cbl-logistica",
|
675 |
+
"name": "CBL Logistica",
|
676 |
+
"other_name": "",
|
677 |
+
"required_fields": []
|
678 |
+
},
|
679 |
+
{
|
680 |
+
"slug": "cbl-logistica-api",
|
681 |
+
"name": "CBL Logistica (API)",
|
682 |
+
"other_name": "",
|
683 |
+
"required_fields": []
|
684 |
+
},
|
685 |
+
{
|
686 |
+
"slug": "cdek",
|
687 |
+
"name": "CDEK",
|
688 |
+
"other_name": null,
|
689 |
+
"required_fields": []
|
690 |
+
},
|
691 |
+
{
|
692 |
+
"slug": "cdek-tr",
|
693 |
+
"name": "CDEK TR",
|
694 |
+
"other_name": "",
|
695 |
+
"required_fields": []
|
696 |
+
},
|
697 |
+
{
|
698 |
+
"slug": "cdldelivers",
|
699 |
+
"name": "CDL Last Mile",
|
700 |
+
"other_name": null,
|
701 |
+
"required_fields": []
|
702 |
+
},
|
703 |
+
{
|
704 |
+
"slug": "celeritas",
|
705 |
+
"name": "Celeritas Transporte, S.L",
|
706 |
+
"other_name": "",
|
707 |
+
"required_fields": []
|
708 |
+
},
|
709 |
+
{
|
710 |
+
"slug": "cello-square",
|
711 |
+
"name": "Cello Square",
|
712 |
+
"other_name": "",
|
713 |
+
"required_fields": []
|
714 |
+
},
|
715 |
+
{
|
716 |
+
"slug": "ceska-posta",
|
717 |
+
"name": "Česká Pošta",
|
718 |
+
"other_name": "Czech Post",
|
719 |
+
"required_fields": []
|
720 |
+
},
|
721 |
+
{
|
722 |
+
"slug": "ceva",
|
723 |
+
"name": "CEVA LOGISTICS",
|
724 |
+
"other_name": "",
|
725 |
+
"required_fields": []
|
726 |
+
},
|
727 |
+
{
|
728 |
+
"slug": "ceva-tracking",
|
729 |
+
"name": "CEVA Package",
|
730 |
+
"other_name": "",
|
731 |
+
"required_fields": []
|
732 |
+
},
|
733 |
+
{
|
734 |
+
"slug": "cfl-logistics",
|
735 |
+
"name": "CFL Logistics",
|
736 |
+
"other_name": "",
|
737 |
+
"required_fields": []
|
738 |
+
},
|
739 |
+
{
|
740 |
+
"slug": "cgs-express",
|
741 |
+
"name": "CGS Express",
|
742 |
+
"other_name": "超光速",
|
743 |
+
"required_fields": []
|
744 |
+
},
|
745 |
+
{
|
746 |
+
"slug": "champion-logistics",
|
747 |
+
"name": "Champion Logistics",
|
748 |
+
"other_name": "Champlog",
|
749 |
+
"required_fields": []
|
750 |
+
},
|
751 |
+
{
|
752 |
+
"slug": "china-ems",
|
753 |
+
"name": "China EMS (ePacket)",
|
754 |
+
"other_name": "中国邮政速递物流, ePacket, e-Packet, e Packet",
|
755 |
+
"required_fields": []
|
756 |
+
},
|
757 |
+
{
|
758 |
+
"slug": "china-post",
|
759 |
+
"name": "China Post",
|
760 |
+
"other_name": "中国邮政",
|
761 |
+
"required_fields": []
|
762 |
+
},
|
763 |
+
{
|
764 |
+
"slug": "chitchats",
|
765 |
+
"name": "Chit Chats",
|
766 |
+
"other_name": "",
|
767 |
+
"required_fields": []
|
768 |
+
},
|
769 |
+
{
|
770 |
+
"slug": "chrobinson",
|
771 |
+
"name": "C.H. Robinson Worldwide, Inc.",
|
772 |
+
"other_name": "",
|
773 |
+
"required_fields": [
|
774 |
+
"tracking_key"
|
775 |
+
]
|
776 |
+
},
|
777 |
+
{
|
778 |
+
"slug": "chronopost-france",
|
779 |
+
"name": "Chronopost France",
|
780 |
+
"other_name": "La Poste EMS",
|
781 |
+
"required_fields": []
|
782 |
+
},
|
783 |
+
{
|
784 |
+
"slug": "chronopost-portugal",
|
785 |
+
"name": "Chronopost Portugal(DPD)",
|
786 |
+
"other_name": "Chronopost pt",
|
787 |
+
"required_fields": []
|
788 |
+
},
|
789 |
+
{
|
790 |
+
"slug": "citylinkexpress",
|
791 |
+
"name": "City-Link Express",
|
792 |
+
"other_name": "Citylink Malaysia",
|
793 |
+
"required_fields": []
|
794 |
+
},
|
795 |
+
{
|
796 |
+
"slug": "cj-gls",
|
797 |
+
"name": "CJ GLS",
|
798 |
+
"other_name": "CJ Korea Express, 씨제이지엘에스주식회사",
|
799 |
+
"required_fields": []
|
800 |
+
},
|
801 |
+
{
|
802 |
+
"slug": "cj-hk-international",
|
803 |
+
"name": "CJ Logistics International(Hong Kong)",
|
804 |
+
"other_name": null,
|
805 |
+
"required_fields": []
|
806 |
+
},
|
807 |
+
{
|
808 |
+
"slug": "cj-korea-thai",
|
809 |
+
"name": "CJ Korea Express",
|
810 |
+
"other_name": "",
|
811 |
+
"required_fields": []
|
812 |
+
},
|
813 |
+
{
|
814 |
+
"slug": "cj-malaysia",
|
815 |
+
"name": "CJ Century",
|
816 |
+
"other_name": "CJ Logistics Malaysia",
|
817 |
+
"required_fields": []
|
818 |
+
},
|
819 |
+
{
|
820 |
+
"slug": "cj-malaysia-international",
|
821 |
+
"name": "CJ Century (International)",
|
822 |
+
"other_name": "CJ Logistics",
|
823 |
+
"required_fields": []
|
824 |
+
},
|
825 |
+
{
|
826 |
+
"slug": "cj-philippines",
|
827 |
+
"name": "CJ Transnational Philippines",
|
828 |
+
"other_name": "",
|
829 |
+
"required_fields": []
|
830 |
+
},
|
831 |
+
{
|
832 |
+
"slug": "cjlogistics",
|
833 |
+
"name": "CJ Logistics International",
|
834 |
+
"other_name": "",
|
835 |
+
"required_fields": []
|
836 |
+
},
|
837 |
+
{
|
838 |
+
"slug": "cjpacket",
|
839 |
+
"name": "CJ Packet",
|
840 |
+
"other_name": "",
|
841 |
+
"required_fields": []
|
842 |
+
},
|
843 |
+
{
|
844 |
+
"slug": "cle-logistics",
|
845 |
+
"name": "CL E-Logistics Solutions Limited",
|
846 |
+
"other_name": "",
|
847 |
+
"required_fields": []
|
848 |
+
},
|
849 |
+
{
|
850 |
+
"slug": "clevy-links",
|
851 |
+
"name": "Clevy Links",
|
852 |
+
"other_name": "",
|
853 |
+
"required_fields": []
|
854 |
+
},
|
855 |
+
{
|
856 |
+
"slug": "cloudwish-asia",
|
857 |
+
"name": "Cloudwish Asia",
|
858 |
+
"other_name": "",
|
859 |
+
"required_fields": []
|
860 |
+
},
|
861 |
+
{
|
862 |
+
"slug": "cndexpress",
|
863 |
+
"name": "CND Express",
|
864 |
+
"other_name": "辰诺达",
|
865 |
+
"required_fields": []
|
866 |
+
},
|
867 |
+
{
|
868 |
+
"slug": "cnexps",
|
869 |
+
"name": "CNE Express",
|
870 |
+
"other_name": "国际快递",
|
871 |
+
"required_fields": []
|
872 |
+
},
|
873 |
+
{
|
874 |
+
"slug": "cnwangtong",
|
875 |
+
"name": "cnwangtong",
|
876 |
+
"other_name": null,
|
877 |
+
"required_fields": []
|
878 |
+
},
|
879 |
+
{
|
880 |
+
"slug": "colis-prive",
|
881 |
+
"name": "Colis Privé",
|
882 |
+
"other_name": "ColisPrivé",
|
883 |
+
"required_fields": [
|
884 |
+
"tracking_postal_code"
|
885 |
+
]
|
886 |
+
},
|
887 |
+
{
|
888 |
+
"slug": "colissimo",
|
889 |
+
"name": "Colissimo",
|
890 |
+
"other_name": "Colissimo fr",
|
891 |
+
"required_fields": []
|
892 |
+
},
|
893 |
+
{
|
894 |
+
"slug": "collectco",
|
895 |
+
"name": "CollectCo",
|
896 |
+
"other_name": "",
|
897 |
+
"required_fields": []
|
898 |
+
},
|
899 |
+
{
|
900 |
+
"slug": "collectplus",
|
901 |
+
"name": "Collect+",
|
902 |
+
"other_name": "Collect Plus UK",
|
903 |
+
"required_fields": []
|
904 |
+
},
|
905 |
+
{
|
906 |
+
"slug": "collivery",
|
907 |
+
"name": "MDS Collivery Pty (Ltd)",
|
908 |
+
"other_name": "",
|
909 |
+
"required_fields": []
|
910 |
+
},
|
911 |
+
{
|
912 |
+
"slug": "comet-tech",
|
913 |
+
"name": "CometTech",
|
914 |
+
"other_name": "彗星科技",
|
915 |
+
"required_fields": []
|
916 |
+
},
|
917 |
+
{
|
918 |
+
"slug": "con-way",
|
919 |
+
"name": "Con-way Freight",
|
920 |
+
"other_name": "Conway",
|
921 |
+
"required_fields": []
|
922 |
+
},
|
923 |
+
{
|
924 |
+
"slug": "continental",
|
925 |
+
"name": "Continental",
|
926 |
+
"other_name": "",
|
927 |
+
"required_fields": []
|
928 |
+
},
|
929 |
+
{
|
930 |
+
"slug": "copa-courier",
|
931 |
+
"name": "Copa Airlines Courier",
|
932 |
+
"other_name": "Copa Courier",
|
933 |
+
"required_fields": []
|
934 |
+
},
|
935 |
+
{
|
936 |
+
"slug": "cope",
|
937 |
+
"name": "Cope Sensitive Freight",
|
938 |
+
"other_name": "",
|
939 |
+
"required_fields": []
|
940 |
+
},
|
941 |
+
{
|
942 |
+
"slug": "corporatecouriers-webhook",
|
943 |
+
"name": "Corporate Couriers",
|
944 |
+
"other_name": null,
|
945 |
+
"required_fields": []
|
946 |
+
},
|
947 |
+
{
|
948 |
+
"slug": "correos-de-mexico",
|
949 |
+
"name": "Correos de Mexico",
|
950 |
+
"other_name": "Mexico Post",
|
951 |
+
"required_fields": []
|
952 |
+
},
|
953 |
+
{
|
954 |
+
"slug": "correosexpress",
|
955 |
+
"name": "Correos Express",
|
956 |
+
"other_name": "",
|
957 |
+
"required_fields": []
|
958 |
+
},
|
959 |
+
{
|
960 |
+
"slug": "correosexpress-api",
|
961 |
+
"name": "Correos Express (API)",
|
962 |
+
"other_name": "",
|
963 |
+
"required_fields": []
|
964 |
+
},
|
965 |
+
{
|
966 |
+
"slug": "costmeticsnow",
|
967 |
+
"name": "Cosmetics Now",
|
968 |
+
"other_name": "CosmeticsNow",
|
969 |
+
"required_fields": []
|
970 |
+
},
|
971 |
+
{
|
972 |
+
"slug": "courant-plus",
|
973 |
+
"name": "Courant Plus",
|
974 |
+
"other_name": null,
|
975 |
+
"required_fields": [
|
976 |
+
"tracking_account_number"
|
977 |
+
]
|
978 |
+
},
|
979 |
+
{
|
980 |
+
"slug": "courex",
|
981 |
+
"name": "Urbanfox",
|
982 |
+
"other_name": "",
|
983 |
+
"required_fields": []
|
984 |
+
},
|
985 |
+
{
|
986 |
+
"slug": "courier-plus",
|
987 |
+
"name": "Courier Plus",
|
988 |
+
"other_name": "Courier Plus",
|
989 |
+
"required_fields": []
|
990 |
+
},
|
991 |
+
{
|
992 |
+
"slug": "courierit",
|
993 |
+
"name": "Courier IT",
|
994 |
+
"other_name": "Courierit",
|
995 |
+
"required_fields": []
|
996 |
+
},
|
997 |
+
{
|
998 |
+
"slug": "courierpost",
|
999 |
+
"name": "CourierPost",
|
1000 |
+
"other_name": "Express Couriers",
|
1001 |
+
"required_fields": []
|
1002 |
+
},
|
1003 |
+
{
|
1004 |
+
"slug": "couriers-please",
|
1005 |
+
"name": "Couriers Please",
|
1006 |
+
"other_name": "CouriersPlease",
|
1007 |
+
"required_fields": []
|
1008 |
+
},
|
1009 |
+
{
|
1010 |
+
"slug": "cpacket",
|
1011 |
+
"name": "cPacket",
|
1012 |
+
"other_name": "u52a0u90aeu5b9d",
|
1013 |
+
"required_fields": []
|
1014 |
+
},
|
1015 |
+
{
|
1016 |
+
"slug": "croshot",
|
1017 |
+
"name": "Croshot",
|
1018 |
+
"other_name": null,
|
1019 |
+
"required_fields": []
|
1020 |
+
},
|
1021 |
+
{
|
1022 |
+
"slug": "ctc-express",
|
1023 |
+
"name": "CTC Express",
|
1024 |
+
"other_name": "",
|
1025 |
+
"required_fields": []
|
1026 |
+
},
|
1027 |
+
{
|
1028 |
+
"slug": "cubyn",
|
1029 |
+
"name": "Cubyn",
|
1030 |
+
"other_name": "",
|
1031 |
+
"required_fields": []
|
1032 |
+
},
|
1033 |
+
{
|
1034 |
+
"slug": "cuckooexpress",
|
1035 |
+
"name": "Cuckoo Express",
|
1036 |
+
"other_name": "布谷鸟",
|
1037 |
+
"required_fields": []
|
1038 |
+
},
|
1039 |
+
{
|
1040 |
+
"slug": "cyprus-post",
|
1041 |
+
"name": "Cyprus Post",
|
1042 |
+
"other_name": "ΚΥΠΡΙΑΚΑ ΤΑΧΥΔΡΟΜΕΙΑ",
|
1043 |
+
"required_fields": []
|
1044 |
+
},
|
1045 |
+
{
|
1046 |
+
"slug": "dachser",
|
1047 |
+
"name": "DACHSER",
|
1048 |
+
"other_name": "Azkar",
|
1049 |
+
"required_fields": []
|
1050 |
+
},
|
1051 |
+
{
|
1052 |
+
"slug": "dajin",
|
1053 |
+
"name": "Shanghai Aqrum Chemical Logistics Co.Ltd",
|
1054 |
+
"other_name": "Dajin",
|
1055 |
+
"required_fields": []
|
1056 |
+
},
|
1057 |
+
{
|
1058 |
+
"slug": "danmark-post",
|
1059 |
+
"name": "PostNord Denmark",
|
1060 |
+
"other_name": "Danmark Post",
|
1061 |
+
"required_fields": []
|
1062 |
+
},
|
1063 |
+
{
|
1064 |
+
"slug": "danske-fragt",
|
1065 |
+
"name": "Danske Fragtmænd",
|
1066 |
+
"other_name": "Fragt DK",
|
1067 |
+
"required_fields": []
|
1068 |
+
},
|
1069 |
+
{
|
1070 |
+
"slug": "dao365",
|
1071 |
+
"name": "DAO365",
|
1072 |
+
"other_name": "",
|
1073 |
+
"required_fields": []
|
1074 |
+
},
|
1075 |
+
{
|
1076 |
+
"slug": "dawnwing",
|
1077 |
+
"name": "Dawn Wing",
|
1078 |
+
"other_name": "DPD Laser Express Logistics",
|
1079 |
+
"required_fields": []
|
1080 |
+
},
|
1081 |
+
{
|
1082 |
+
"slug": "dayton-freight",
|
1083 |
+
"name": "Dayton Freight",
|
1084 |
+
"other_name": "",
|
1085 |
+
"required_fields": []
|
1086 |
+
},
|
1087 |
+
{
|
1088 |
+
"slug": "dbschenker-se",
|
1089 |
+
"name": "DB Schenker",
|
1090 |
+
"other_name": "Deutsche Bahn",
|
1091 |
+
"required_fields": []
|
1092 |
+
},
|
1093 |
+
{
|
1094 |
+
"slug": "dbschenker-sv",
|
1095 |
+
"name": "DB Schenker Sweden",
|
1096 |
+
"other_name": "",
|
1097 |
+
"required_fields": []
|
1098 |
+
},
|
1099 |
+
{
|
1100 |
+
"slug": "ddexpress",
|
1101 |
+
"name": "DD Express Courier",
|
1102 |
+
"other_name": "",
|
1103 |
+
"required_fields": []
|
1104 |
+
},
|
1105 |
+
{
|
1106 |
+
"slug": "delcart-in",
|
1107 |
+
"name": "Delcart",
|
1108 |
+
"other_name": "",
|
1109 |
+
"required_fields": []
|
1110 |
+
},
|
1111 |
+
{
|
1112 |
+
"slug": "delhivery",
|
1113 |
+
"name": "Delhivery",
|
1114 |
+
"other_name": "Gharpay",
|
1115 |
+
"required_fields": []
|
1116 |
+
},
|
1117 |
+
{
|
1118 |
+
"slug": "deliveryontime",
|
1119 |
+
"name": "DELIVERYONTIME LOGISTICS PVT LTD",
|
1120 |
+
"other_name": "",
|
1121 |
+
"required_fields": []
|
1122 |
+
},
|
1123 |
+
{
|
1124 |
+
"slug": "delnext",
|
1125 |
+
"name": "Delnext",
|
1126 |
+
"other_name": "",
|
1127 |
+
"required_fields": []
|
1128 |
+
},
|
1129 |
+
{
|
1130 |
+
"slug": "deltec-courier",
|
1131 |
+
"name": "Deltec Courier",
|
1132 |
+
"other_name": "Deltec Interntional Courier",
|
1133 |
+
"required_fields": []
|
1134 |
+
},
|
1135 |
+
{
|
1136 |
+
"slug": "demandship",
|
1137 |
+
"name": "DemandShip",
|
1138 |
+
"other_name": "",
|
1139 |
+
"required_fields": []
|
1140 |
+
},
|
1141 |
+
{
|
1142 |
+
"slug": "descartes",
|
1143 |
+
"name": "Innovel",
|
1144 |
+
"other_name": "",
|
1145 |
+
"required_fields": []
|
1146 |
+
},
|
1147 |
+
{
|
1148 |
+
"slug": "designertransport-webhook",
|
1149 |
+
"name": "Designer Transport",
|
1150 |
+
"other_name": null,
|
1151 |
+
"required_fields": []
|
1152 |
+
},
|
1153 |
+
{
|
1154 |
+
"slug": "destiny",
|
1155 |
+
"name": "Destiny Transportation",
|
1156 |
+
"other_name": null,
|
1157 |
+
"required_fields": []
|
1158 |
+
},
|
1159 |
+
{
|
1160 |
+
"slug": "detrack",
|
1161 |
+
"name": "Detrack",
|
1162 |
+
"other_name": "Detrack Singapore",
|
1163 |
+
"required_fields": []
|
1164 |
+
},
|
1165 |
+
{
|
1166 |
+
"slug": "deutsch-post",
|
1167 |
+
"name": "Deutsche Post Mail",
|
1168 |
+
"other_name": "dpdhl",
|
1169 |
+
"required_fields": [
|
1170 |
+
"tracking_ship_date"
|
1171 |
+
]
|
1172 |
+
},
|
1173 |
+
{
|
1174 |
+
"slug": "dex-i",
|
1175 |
+
"name": "DEX-I",
|
1176 |
+
"other_name": "",
|
1177 |
+
"required_fields": []
|
1178 |
+
},
|
1179 |
+
{
|
1180 |
+
"slug": "dhl",
|
1181 |
+
"name": "DHL Express",
|
1182 |
+
"other_name": "DHL International",
|
1183 |
+
"required_fields": []
|
1184 |
+
},
|
1185 |
+
{
|
1186 |
+
"slug": "dhl-active-tracing",
|
1187 |
+
"name": "DHL Active Tracing",
|
1188 |
+
"other_name": "",
|
1189 |
+
"required_fields": []
|
1190 |
+
},
|
1191 |
+
{
|
1192 |
+
"slug": "dhl-benelux",
|
1193 |
+
"name": "DHL Benelux",
|
1194 |
+
"other_name": "DHL TrackNet Benelux",
|
1195 |
+
"required_fields": []
|
1196 |
+
},
|
1197 |
+
{
|
1198 |
+
"slug": "dhl-deliverit",
|
1199 |
+
"name": "DHL 2-Mann-Handling",
|
1200 |
+
"other_name": "DHL Deliver IT",
|
1201 |
+
"required_fields": []
|
1202 |
+
},
|
1203 |
+
{
|
1204 |
+
"slug": "dhl-es",
|
1205 |
+
"name": "DHL Spain Domestic",
|
1206 |
+
"other_name": "DHL España",
|
1207 |
+
"required_fields": []
|
1208 |
+
},
|
1209 |
+
{
|
1210 |
+
"slug": "dhl-germany",
|
1211 |
+
"name": "Deutsche Post DHL",
|
1212 |
+
"other_name": "DHL Germany",
|
1213 |
+
"required_fields": []
|
1214 |
+
},
|
1215 |
+
{
|
1216 |
+
"slug": "dhl-germany-ftp",
|
1217 |
+
"name": "Deutsche Post DHL (FTP)",
|
1218 |
+
"other_name": "",
|
1219 |
+
"required_fields": []
|
1220 |
+
},
|
1221 |
+
{
|
1222 |
+
"slug": "dhl-global-forwarding",
|
1223 |
+
"name": "DHL Global Forwarding",
|
1224 |
+
"other_name": "DHL Logistics",
|
1225 |
+
"required_fields": []
|
1226 |
+
},
|
1227 |
+
{
|
1228 |
+
"slug": "dhl-global-mail",
|
1229 |
+
"name": "DHL eCommerce US",
|
1230 |
+
"other_name": "DHL Global Mail",
|
1231 |
+
"required_fields": []
|
1232 |
+
},
|
1233 |
+
{
|
1234 |
+
"slug": "dhl-global-mail-asia",
|
1235 |
+
"name": "DHL eCommerce Asia",
|
1236 |
+
"other_name": "DGM Asia",
|
1237 |
+
"required_fields": []
|
1238 |
+
},
|
1239 |
+
{
|
1240 |
+
"slug": "dhl-global-mail-asia-api",
|
1241 |
+
"name": "DHL eCommerce Asia (API)",
|
1242 |
+
"other_name": "",
|
1243 |
+
"required_fields": []
|
1244 |
+
},
|
1245 |
+
{
|
1246 |
+
"slug": "dhl-hk",
|
1247 |
+
"name": "DHL Hong Kong",
|
1248 |
+
"other_name": "DHL HK Domestic",
|
1249 |
+
"required_fields": []
|
1250 |
+
},
|
1251 |
+
{
|
1252 |
+
"slug": "dhl-nl",
|
1253 |
+
"name": "DHL Netherlands",
|
1254 |
+
"other_name": "DHL Nederlands",
|
1255 |
+
"required_fields": []
|
1256 |
+
},
|
1257 |
+
{
|
1258 |
+
"slug": "dhl-pieceid",
|
1259 |
+
"name": "DHL Express (Piece ID)",
|
1260 |
+
"other_name": "DHL International",
|
1261 |
+
"required_fields": []
|
1262 |
+
},
|
1263 |
+
{
|
1264 |
+
"slug": "dhl-poland",
|
1265 |
+
"name": "DHL Poland Domestic",
|
1266 |
+
"other_name": "DHL Polska",
|
1267 |
+
"required_fields": []
|
1268 |
+
},
|
1269 |
+
{
|
1270 |
+
"slug": "dhl-reference",
|
1271 |
+
"name": "DHl (Reference number)",
|
1272 |
+
"other_name": null,
|
1273 |
+
"required_fields": [
|
1274 |
+
"tracking_ship_date"
|
1275 |
+
]
|
1276 |
+
},
|
1277 |
+
{
|
1278 |
+
"slug": "dhl-supply-chain-au",
|
1279 |
+
"name": "DHL Supply Chain Australia",
|
1280 |
+
"other_name": "DHL ConnectedView",
|
1281 |
+
"required_fields": []
|
1282 |
+
},
|
1283 |
+
{
|
1284 |
+
"slug": "dhl-supplychain-id",
|
1285 |
+
"name": "DHL Supply Chain Indonesia",
|
1286 |
+
"other_name": "",
|
1287 |
+
"required_fields": []
|
1288 |
+
},
|
1289 |
+
{
|
1290 |
+
"slug": "dhl-supplychain-in",
|
1291 |
+
"name": "DHL supply chain India",
|
1292 |
+
"other_name": "",
|
1293 |
+
"required_fields": []
|
1294 |
+
},
|
1295 |
+
{
|
1296 |
+
"slug": "dhlparcel-es",
|
1297 |
+
"name": "DHL Parcel Spain",
|
1298 |
+
"other_name": "",
|
1299 |
+
"required_fields": []
|
1300 |
+
},
|
1301 |
+
{
|
1302 |
+
"slug": "dhlparcel-nl",
|
1303 |
+
"name": "DHL Parcel NL",
|
1304 |
+
"other_name": "Selektvracht, dhlparcel.nl",
|
1305 |
+
"required_fields": []
|
1306 |
+
},
|
1307 |
+
{
|
1308 |
+
"slug": "dhlparcel-uk",
|
1309 |
+
"name": "DHL Parcel UK",
|
1310 |
+
"other_name": "",
|
1311 |
+
"required_fields": []
|
1312 |
+
},
|
1313 |
+
{
|
1314 |
+
"slug": "dicom",
|
1315 |
+
"name": "GLS Logistic Systems Canada Ltd./Dicom",
|
1316 |
+
"other_name": null,
|
1317 |
+
"required_fields": []
|
1318 |
+
},
|
1319 |
+
{
|
1320 |
+
"slug": "dimerco",
|
1321 |
+
"name": "Dimerco Express Group",
|
1322 |
+
"other_name": "",
|
1323 |
+
"required_fields": []
|
1324 |
+
},
|
1325 |
+
{
|
1326 |
+
"slug": "directfreight-au-ref",
|
1327 |
+
"name": "Direct Freight Express",
|
1328 |
+
"other_name": null,
|
1329 |
+
"required_fields": []
|
1330 |
+
},
|
1331 |
+
{
|
1332 |
+
"slug": "directlog",
|
1333 |
+
"name": "Directlog",
|
1334 |
+
"other_name": "Direct Express",
|
1335 |
+
"required_fields": []
|
1336 |
+
},
|
1337 |
+
{
|
1338 |
+
"slug": "dmm-network",
|
1339 |
+
"name": "DMM Network",
|
1340 |
+
"other_name": "dmmnetwork.it",
|
1341 |
+
"required_fields": []
|
1342 |
+
},
|
1343 |
+
{
|
1344 |
+
"slug": "dms-matrix",
|
1345 |
+
"name": "DMSMatrix",
|
1346 |
+
"other_name": "",
|
1347 |
+
"required_fields": []
|
1348 |
+
},
|
1349 |
+
{
|
1350 |
+
"slug": "dnj-express",
|
1351 |
+
"name": "DNJ Express",
|
1352 |
+
"other_name": "",
|
1353 |
+
"required_fields": []
|
1354 |
+
},
|
1355 |
+
{
|
1356 |
+
"slug": "doora",
|
1357 |
+
"name": "Doora Logistics",
|
1358 |
+
"other_name": "",
|
1359 |
+
"required_fields": []
|
1360 |
+
},
|
1361 |
+
{
|
1362 |
+
"slug": "doordash-webhook",
|
1363 |
+
"name": "DoorDash",
|
1364 |
+
"other_name": "",
|
1365 |
+
"required_fields": []
|
1366 |
+
},
|
1367 |
+
{
|
1368 |
+
"slug": "dotzot",
|
1369 |
+
"name": "Dotzot",
|
1370 |
+
"other_name": "Dotzot",
|
1371 |
+
"required_fields": []
|
1372 |
+
},
|
1373 |
+
{
|
1374 |
+
"slug": "dpd",
|
1375 |
+
"name": "DPD",
|
1376 |
+
"other_name": "Dynamic Parcel Distribution",
|
1377 |
+
"required_fields": []
|
1378 |
+
},
|
1379 |
+
{
|
1380 |
+
"slug": "dpd-de",
|
1381 |
+
"name": "DPD Germany",
|
1382 |
+
"other_name": "DPD Germany",
|
1383 |
+
"required_fields": []
|
1384 |
+
},
|
1385 |
+
{
|
1386 |
+
"slug": "dpd-fr-reference",
|
1387 |
+
"name": "DPD France",
|
1388 |
+
"other_name": "",
|
1389 |
+
"required_fields": [
|
1390 |
+
"tracking_account_number"
|
1391 |
+
]
|
1392 |
+
},
|
1393 |
+
{
|
1394 |
+
"slug": "dpd-hk",
|
1395 |
+
"name": "DPD HK",
|
1396 |
+
"other_name": "",
|
1397 |
+
"required_fields": []
|
1398 |
+
},
|
1399 |
+
{
|
1400 |
+
"slug": "dpd-ireland",
|
1401 |
+
"name": "DPD Ireland",
|
1402 |
+
"other_name": "DPD ie",
|
1403 |
+
"required_fields": []
|
1404 |
+
},
|
1405 |
+
{
|
1406 |
+
"slug": "dpd-poland",
|
1407 |
+
"name": "DPD Poland",
|
1408 |
+
"other_name": "Dynamic Parcel Distribution Poland",
|
1409 |
+
"required_fields": []
|
1410 |
+
},
|
1411 |
+
{
|
1412 |
+
"slug": "dpd-ro",
|
1413 |
+
"name": "DPD Romania",
|
1414 |
+
"other_name": "",
|
1415 |
+
"required_fields": []
|
1416 |
+
},
|
1417 |
+
{
|
1418 |
+
"slug": "dpd-ru",
|
1419 |
+
"name": "DPD Russia",
|
1420 |
+
"other_name": "",
|
1421 |
+
"required_fields": []
|
1422 |
+
},
|
1423 |
+
{
|
1424 |
+
"slug": "dpd-uk",
|
1425 |
+
"name": "DPD UK",
|
1426 |
+
"other_name": "Dynamic Parcel Distribution UK",
|
1427 |
+
"required_fields": []
|
1428 |
+
},
|
1429 |
+
{
|
1430 |
+
"slug": "dpe-express",
|
1431 |
+
"name": "DPE Express",
|
1432 |
+
"other_name": "Delivery Perfect Express Co.",
|
1433 |
+
"required_fields": []
|
1434 |
+
},
|
1435 |
+
{
|
1436 |
+
"slug": "dpe-za",
|
1437 |
+
"name": "DPE South Africa",
|
1438 |
+
"other_name": "DPE Worldwide Express",
|
1439 |
+
"required_fields": []
|
1440 |
+
},
|
1441 |
+
{
|
1442 |
+
"slug": "dpex",
|
1443 |
+
"name": "DPEX",
|
1444 |
+
"other_name": "TGX, Toll Global Express Asia",
|
1445 |
+
"required_fields": []
|
1446 |
+
},
|
1447 |
+
{
|
1448 |
+
"slug": "dsv",
|
1449 |
+
"name": "DSV",
|
1450 |
+
"other_name": "",
|
1451 |
+
"required_fields": []
|
1452 |
+
},
|
1453 |
+
{
|
1454 |
+
"slug": "dtdc",
|
1455 |
+
"name": "DTDC India",
|
1456 |
+
"other_name": "DTDC Courier & Cargo",
|
1457 |
+
"required_fields": []
|
1458 |
+
},
|
1459 |
+
{
|
1460 |
+
"slug": "dtdc-au",
|
1461 |
+
"name": "DTDC Australia",
|
1462 |
+
"other_name": "",
|
1463 |
+
"required_fields": []
|
1464 |
+
},
|
1465 |
+
{
|
1466 |
+
"slug": "dtdc-express",
|
1467 |
+
"name": "DTDC Express Global PTE LTD",
|
1468 |
+
"other_name": "",
|
1469 |
+
"required_fields": []
|
1470 |
+
},
|
1471 |
+
{
|
1472 |
+
"slug": "dx",
|
1473 |
+
"name": "DX",
|
1474 |
+
"other_name": "-",
|
1475 |
+
"required_fields": [
|
1476 |
+
"tracking_account_number"
|
1477 |
+
]
|
1478 |
+
},
|
1479 |
+
{
|
1480 |
+
"slug": "dx-b2b-connum",
|
1481 |
+
"name": "DX (B2B)",
|
1482 |
+
"other_name": null,
|
1483 |
+
"required_fields": []
|
1484 |
+
},
|
1485 |
+
{
|
1486 |
+
"slug": "dx-freight",
|
1487 |
+
"name": "DX Freight",
|
1488 |
+
"other_name": "",
|
1489 |
+
"required_fields": []
|
1490 |
+
},
|
1491 |
+
{
|
1492 |
+
"slug": "dx-sftp",
|
1493 |
+
"name": "DX (SFTP)",
|
1494 |
+
"other_name": "",
|
1495 |
+
"required_fields": []
|
1496 |
+
},
|
1497 |
+
{
|
1498 |
+
"slug": "dylt",
|
1499 |
+
"name": "Daylight Transport, LLC",
|
1500 |
+
"other_name": "",
|
1501 |
+
"required_fields": []
|
1502 |
+
},
|
1503 |
+
{
|
1504 |
+
"slug": "dynamic-logistics",
|
1505 |
+
"name": "Dynamic Logistics",
|
1506 |
+
"other_name": "Dynamic Logistics Thailand",
|
1507 |
+
"required_fields": [
|
1508 |
+
"tracking_account_number"
|
1509 |
+
]
|
1510 |
+
},
|
1511 |
+
{
|
1512 |
+
"slug": "easy-mail",
|
1513 |
+
"name": "Easy Mail",
|
1514 |
+
"other_name": "",
|
1515 |
+
"required_fields": []
|
1516 |
+
},
|
1517 |
+
{
|
1518 |
+
"slug": "ec-firstclass",
|
1519 |
+
"name": "Chukou1",
|
1520 |
+
"other_name": "出口易、Chukou1、CK1",
|
1521 |
+
"required_fields": []
|
1522 |
+
},
|
1523 |
+
{
|
1524 |
+
"slug": "ecargo-asia",
|
1525 |
+
"name": "Ecargo",
|
1526 |
+
"other_name": "Ecargo Pte. Ltd",
|
1527 |
+
"required_fields": []
|
1528 |
+
},
|
1529 |
+
{
|
1530 |
+
"slug": "echo",
|
1531 |
+
"name": "Echo",
|
1532 |
+
"other_name": "Echo Global Logistics",
|
1533 |
+
"required_fields": []
|
1534 |
+
},
|
1535 |
+
{
|
1536 |
+
"slug": "ecms",
|
1537 |
+
"name": "ECMS International Logistics Co., Ltd.",
|
1538 |
+
"other_name": "",
|
1539 |
+
"required_fields": []
|
1540 |
+
},
|
1541 |
+
{
|
1542 |
+
"slug": "ecom-express",
|
1543 |
+
"name": "Ecom Express",
|
1544 |
+
"other_name": "EcomExpress",
|
1545 |
+
"required_fields": []
|
1546 |
+
},
|
1547 |
+
{
|
1548 |
+
"slug": "ecourier",
|
1549 |
+
"name": "eCourier",
|
1550 |
+
"other_name": "",
|
1551 |
+
"required_fields": []
|
1552 |
+
},
|
1553 |
+
{
|
1554 |
+
"slug": "ecoutier",
|
1555 |
+
"name": "eCoutier",
|
1556 |
+
"other_name": "",
|
1557 |
+
"required_fields": []
|
1558 |
+
},
|
1559 |
+
{
|
1560 |
+
"slug": "efex",
|
1561 |
+
"name": "eFEx (E-Commerce Fulfillment & Express)",
|
1562 |
+
"other_name": "",
|
1563 |
+
"required_fields": []
|
1564 |
+
},
|
1565 |
+
{
|
1566 |
+
"slug": "efs",
|
1567 |
+
"name": "EFS (E-commerce Fulfillment Service)",
|
1568 |
+
"other_name": "",
|
1569 |
+
"required_fields": []
|
1570 |
+
},
|
1571 |
+
{
|
1572 |
+
"slug": "ekart",
|
1573 |
+
"name": "Ekart",
|
1574 |
+
"other_name": "Ekart Logistics",
|
1575 |
+
"required_fields": []
|
1576 |
+
},
|
1577 |
+
{
|
1578 |
+
"slug": "elian-post",
|
1579 |
+
"name": "Yilian (Elian) Supply Chain",
|
1580 |
+
"other_name": null,
|
1581 |
+
"required_fields": []
|
1582 |
+
},
|
1583 |
+
{
|
1584 |
+
"slug": "elogistica",
|
1585 |
+
"name": "ELogistica",
|
1586 |
+
"other_name": null,
|
1587 |
+
"required_fields": []
|
1588 |
+
},
|
1589 |
+
{
|
1590 |
+
"slug": "elta-courier",
|
1591 |
+
"name": "ELTA Hellenic Post",
|
1592 |
+
"other_name": "Greece Post, Ελληνικά Ταχυδρομεία, ELTA Courier, Ταχυμεταφορές ΕΛΤΑ",
|
1593 |
+
"required_fields": []
|
1594 |
+
},
|
1595 |
+
{
|
1596 |
+
"slug": "emirates-post",
|
1597 |
+
"name": "Emirates Post",
|
1598 |
+
"other_name": "مجموعة بريد الإمارات, UAE Post",
|
1599 |
+
"required_fields": []
|
1600 |
+
},
|
1601 |
+
{
|
1602 |
+
"slug": "empsexpress",
|
1603 |
+
"name": "EMPS Express",
|
1604 |
+
"other_name": "快信快包",
|
1605 |
+
"required_fields": []
|
1606 |
+
},
|
1607 |
+
{
|
1608 |
+
"slug": "endeavour-delivery",
|
1609 |
+
"name": "Endeavour Delivery",
|
1610 |
+
"other_name": "",
|
1611 |
+
"required_fields": [
|
1612 |
+
"tracking_postal_code"
|
1613 |
+
]
|
1614 |
+
},
|
1615 |
+
{
|
1616 |
+
"slug": "ensenda",
|
1617 |
+
"name": "Ensenda",
|
1618 |
+
"other_name": "",
|
1619 |
+
"required_fields": []
|
1620 |
+
},
|
1621 |
+
{
|
1622 |
+
"slug": "envialia",
|
1623 |
+
"name": "Envialia",
|
1624 |
+
"other_name": "Envialia Spain",
|
1625 |
+
"required_fields": []
|
1626 |
+
},
|
1627 |
+
{
|
1628 |
+
"slug": "ep-box",
|
1629 |
+
"name": "EP-Box",
|
1630 |
+
"other_name": "",
|
1631 |
+
"required_fields": []
|
1632 |
+
},
|
1633 |
+
{
|
1634 |
+
"slug": "eparcel-kr",
|
1635 |
+
"name": "eParcel Korea",
|
1636 |
+
"other_name": "Yong Seoung",
|
1637 |
+
"required_fields": []
|
1638 |
+
},
|
1639 |
+
{
|
1640 |
+
"slug": "equick-cn",
|
1641 |
+
"name": "Equick China",
|
1642 |
+
"other_name": "北京网易速达",
|
1643 |
+
"required_fields": []
|
1644 |
+
},
|
1645 |
+
{
|
1646 |
+
"slug": "eshipping",
|
1647 |
+
"name": "Eshipping",
|
1648 |
+
"other_name": "Eshipping Global Supply Chain Management(Shenzhen)Co. Ltd",
|
1649 |
+
"required_fields": []
|
1650 |
+
},
|
1651 |
+
{
|
1652 |
+
"slug": "estafeta",
|
1653 |
+
"name": "Estafeta",
|
1654 |
+
"other_name": "Estafeta Mexicana",
|
1655 |
+
"required_fields": []
|
1656 |
+
},
|
1657 |
+
{
|
1658 |
+
"slug": "estes",
|
1659 |
+
"name": "Estes",
|
1660 |
+
"other_name": "Estes Express Lines",
|
1661 |
+
"required_fields": []
|
1662 |
+
},
|
1663 |
+
{
|
1664 |
+
"slug": "etomars",
|
1665 |
+
"name": "Etomars",
|
1666 |
+
"other_name": "",
|
1667 |
+
"required_fields": []
|
1668 |
+
},
|
1669 |
+
{
|
1670 |
+
"slug": "etotal",
|
1671 |
+
"name": "eTotal Solution Limited",
|
1672 |
+
"other_name": "",
|
1673 |
+
"required_fields": []
|
1674 |
+
},
|
1675 |
+
{
|
1676 |
+
"slug": "ets-express",
|
1677 |
+
"name": "RETS express",
|
1678 |
+
"other_name": "绥芬河俄通收国际货物运输代理有限责任公司",
|
1679 |
+
"required_fields": []
|
1680 |
+
},
|
1681 |
+
{
|
1682 |
+
"slug": "eu-fleet-solutions",
|
1683 |
+
"name": "EU Fleet Solutions",
|
1684 |
+
"other_name": "",
|
1685 |
+
"required_fields": [
|
1686 |
+
"tracking_postal_code"
|
1687 |
+
]
|
1688 |
+
},
|
1689 |
+
{
|
1690 |
+
"slug": "eurodis",
|
1691 |
+
"name": "Eurodis",
|
1692 |
+
"other_name": "",
|
1693 |
+
"required_fields": []
|
1694 |
+
},
|
1695 |
+
{
|
1696 |
+
"slug": "exapaq",
|
1697 |
+
"name": "DPD France (formerly exapaq)",
|
1698 |
+
"other_name": "Exapaq",
|
1699 |
+
"required_fields": []
|
1700 |
+
},
|
1701 |
+
{
|
1702 |
+
"slug": "expeditors",
|
1703 |
+
"name": "Expeditors",
|
1704 |
+
"other_name": "",
|
1705 |
+
"required_fields": []
|
1706 |
+
},
|
1707 |
+
{
|
1708 |
+
"slug": "expeditors-api",
|
1709 |
+
"name": "Expeditors API",
|
1710 |
+
"other_name": "",
|
1711 |
+
"required_fields": []
|
1712 |
+
},
|
1713 |
+
{
|
1714 |
+
"slug": "expeditors-api-ref",
|
1715 |
+
"name": "Expeditors API Reference",
|
1716 |
+
"other_name": "",
|
1717 |
+
"required_fields": []
|
1718 |
+
},
|
1719 |
+
{
|
1720 |
+
"slug": "expresssale",
|
1721 |
+
"name": "Expresssale",
|
1722 |
+
"other_name": "",
|
1723 |
+
"required_fields": []
|
1724 |
+
},
|
1725 |
+
{
|
1726 |
+
"slug": "ezship",
|
1727 |
+
"name": "EZship",
|
1728 |
+
"other_name": "",
|
1729 |
+
"required_fields": []
|
1730 |
+
},
|
1731 |
+
{
|
1732 |
+
"slug": "fan",
|
1733 |
+
"name": "FAN COURIER EXPRESS",
|
1734 |
+
"other_name": null,
|
1735 |
+
"required_fields": []
|
1736 |
+
},
|
1737 |
+
{
|
1738 |
+
"slug": "far-international",
|
1739 |
+
"name": "FAR international",
|
1740 |
+
"other_name": "",
|
1741 |
+
"required_fields": []
|
1742 |
+
},
|
1743 |
+
{
|
1744 |
+
"slug": "fastrak-th",
|
1745 |
+
"name": "Fastrak Services",
|
1746 |
+
"other_name": "Fastrak Advanced Delivery Systems",
|
1747 |
+
"required_fields": []
|
1748 |
+
},
|
1749 |
+
{
|
1750 |
+
"slug": "fasttrack",
|
1751 |
+
"name": "Fasttrack",
|
1752 |
+
"other_name": "",
|
1753 |
+
"required_fields": []
|
1754 |
+
},
|
1755 |
+
{
|
1756 |
+
"slug": "fastway-au",
|
1757 |
+
"name": "Aramex Australia (formerly Fastway AU)",
|
1758 |
+
"other_name": "Fastway Couriers",
|
1759 |
+
"required_fields": []
|
1760 |
+
},
|
1761 |
+
{
|
1762 |
+
"slug": "fastway-ireland",
|
1763 |
+
"name": "Fastway Ireland",
|
1764 |
+
"other_name": "Fastway Couriers",
|
1765 |
+
"required_fields": []
|
1766 |
+
},
|
1767 |
+
{
|
1768 |
+
"slug": "fastway-nz",
|
1769 |
+
"name": "Fastway New Zealand",
|
1770 |
+
"other_name": "",
|
1771 |
+
"required_fields": []
|
1772 |
+
},
|
1773 |
+
{
|
1774 |
+
"slug": "fastway-za",
|
1775 |
+
"name": "Fastway South Africa",
|
1776 |
+
"other_name": "Fastway Couriers",
|
1777 |
+
"required_fields": []
|
1778 |
+
},
|
1779 |
+
{
|
1780 |
+
"slug": "fedex",
|
1781 |
+
"name": "FedEx",
|
1782 |
+
"other_name": "Federal Express",
|
1783 |
+
"required_fields": []
|
1784 |
+
},
|
1785 |
+
{
|
1786 |
+
"slug": "fedex-crossborder",
|
1787 |
+
"name": "Fedex Cross Border",
|
1788 |
+
"other_name": "",
|
1789 |
+
"required_fields": []
|
1790 |
+
},
|
1791 |
+
{
|
1792 |
+
"slug": "fedex-fims",
|
1793 |
+
"name": "FedEx International MailService",
|
1794 |
+
"other_name": "",
|
1795 |
+
"required_fields": []
|
1796 |
+
},
|
1797 |
+
{
|
1798 |
+
"slug": "fedex-freight",
|
1799 |
+
"name": "FedEx Freight",
|
1800 |
+
"other_name": "FedEx LTL",
|
1801 |
+
"required_fields": []
|
1802 |
+
},
|
1803 |
+
{
|
1804 |
+
"slug": "fedex-uk",
|
1805 |
+
"name": "FedEx UK",
|
1806 |
+
"other_name": "FedEx United Kingdom",
|
1807 |
+
"required_fields": []
|
1808 |
+
},
|
1809 |
+
{
|
1810 |
+
"slug": "fercam",
|
1811 |
+
"name": "FERCAM Logistics & Transport",
|
1812 |
+
"other_name": "FERCAM SpA",
|
1813 |
+
"required_fields": []
|
1814 |
+
},
|
1815 |
+
{
|
1816 |
+
"slug": "fetchr",
|
1817 |
+
"name": "Fetchr",
|
1818 |
+
"other_name": "",
|
1819 |
+
"required_fields": []
|
1820 |
+
},
|
1821 |
+
{
|
1822 |
+
"slug": "fetchr-webhook",
|
1823 |
+
"name": "Mena 360 (Fetchr)",
|
1824 |
+
"other_name": "",
|
1825 |
+
"required_fields": []
|
1826 |
+
},
|
1827 |
+
{
|
1828 |
+
"slug": "first-flight",
|
1829 |
+
"name": "First Flight Couriers",
|
1830 |
+
"other_name": "FirstFlight India",
|
1831 |
+
"required_fields": []
|
1832 |
+
},
|
1833 |
+
{
|
1834 |
+
"slug": "first-logistics",
|
1835 |
+
"name": "First Logistics",
|
1836 |
+
"other_name": "PT Synergy First Logistics",
|
1837 |
+
"required_fields": []
|
1838 |
+
},
|
1839 |
+
{
|
1840 |
+
"slug": "firstmile",
|
1841 |
+
"name": "FirstMile",
|
1842 |
+
"other_name": "",
|
1843 |
+
"required_fields": []
|
1844 |
+
},
|
1845 |
+
{
|
1846 |
+
"slug": "fitzmark-api",
|
1847 |
+
"name": "FitzMark",
|
1848 |
+
"other_name": "",
|
1849 |
+
"required_fields": []
|
1850 |
+
},
|
1851 |
+
{
|
1852 |
+
"slug": "flytexpress",
|
1853 |
+
"name": "Flyt Express",
|
1854 |
+
"other_name": "飞特物流",
|
1855 |
+
"required_fields": []
|
1856 |
+
},
|
1857 |
+
{
|
1858 |
+
"slug": "fmx",
|
1859 |
+
"name": "FMX",
|
1860 |
+
"other_name": "",
|
1861 |
+
"required_fields": []
|
1862 |
+
},
|
1863 |
+
{
|
1864 |
+
"slug": "fonsen",
|
1865 |
+
"name": "Fonsen Logistics",
|
1866 |
+
"other_name": "",
|
1867 |
+
"required_fields": []
|
1868 |
+
},
|
1869 |
+
{
|
1870 |
+
"slug": "forrun",
|
1871 |
+
"name": "forrun Pvt Ltd (Arpatech Venture)",
|
1872 |
+
"other_name": "",
|
1873 |
+
"required_fields": []
|
1874 |
+
},
|
1875 |
+
{
|
1876 |
+
"slug": "freterapido",
|
1877 |
+
"name": "Frete Rápido",
|
1878 |
+
"other_name": "",
|
1879 |
+
"required_fields": []
|
1880 |
+
},
|
1881 |
+
{
|
1882 |
+
"slug": "gati-kwe",
|
1883 |
+
"name": "Gati-KWE",
|
1884 |
+
"other_name": "Gati-Kintetsu Express",
|
1885 |
+
"required_fields": []
|
1886 |
+
},
|
1887 |
+
{
|
1888 |
+
"slug": "gba",
|
1889 |
+
"name": "GBA Services Ltd",
|
1890 |
+
"other_name": "",
|
1891 |
+
"required_fields": []
|
1892 |
+
},
|
1893 |
+
{
|
1894 |
+
"slug": "gbs-broker",
|
1895 |
+
"name": "GBS-Broker",
|
1896 |
+
"other_name": null,
|
1897 |
+
"required_fields": []
|
1898 |
+
},
|
1899 |
+
{
|
1900 |
+
"slug": "gdex",
|
1901 |
+
"name": "GDEX",
|
1902 |
+
"other_name": "GD Express",
|
1903 |
+
"required_fields": []
|
1904 |
+
},
|
1905 |
+
{
|
1906 |
+
"slug": "gemworldwide",
|
1907 |
+
"name": "GEM Worldwide",
|
1908 |
+
"other_name": "",
|
1909 |
+
"required_fields": []
|
1910 |
+
},
|
1911 |
+
{
|
1912 |
+
"slug": "general-overnight",
|
1913 |
+
"name": "Go!Express and logistics",
|
1914 |
+
"other_name": "",
|
1915 |
+
"required_fields": []
|
1916 |
+
},
|
1917 |
+
{
|
1918 |
+
"slug": "geodis-calberson-fr",
|
1919 |
+
"name": "GEODIS - Distribution & Express",
|
1920 |
+
"other_name": "Geodiscalberson",
|
1921 |
+
"required_fields": []
|
1922 |
+
},
|
1923 |
+
{
|
1924 |
+
"slug": "geodis-espace",
|
1925 |
+
"name": "Geodis E-space",
|
1926 |
+
"other_name": "Geodis Distribution & Express",
|
1927 |
+
"required_fields": [
|
1928 |
+
"tracking_key"
|
1929 |
+
]
|
1930 |
+
},
|
1931 |
+
{
|
1932 |
+
"slug": "ghn",
|
1933 |
+
"name": "Giao hàng nhanh",
|
1934 |
+
"other_name": "Giaohangnhanh.vn, GHN",
|
1935 |
+
"required_fields": []
|
1936 |
+
},
|
1937 |
+
{
|
1938 |
+
"slug": "gio-express",
|
1939 |
+
"name": "Gio Express",
|
1940 |
+
"other_name": null,
|
1941 |
+
"required_fields": []
|
1942 |
+
},
|
1943 |
+
{
|
1944 |
+
"slug": "global-express",
|
1945 |
+
"name": "Tai Wan Global Business",
|
1946 |
+
"other_name": "全球商务快递",
|
1947 |
+
"required_fields": []
|
1948 |
+
},
|
1949 |
+
{
|
1950 |
+
"slug": "globaltranz",
|
1951 |
+
"name": "GlobalTranz",
|
1952 |
+
"other_name": "",
|
1953 |
+
"required_fields": []
|
1954 |
+
},
|
1955 |
+
{
|
1956 |
+
"slug": "globegistics",
|
1957 |
+
"name": "Globegistics Inc.",
|
1958 |
+
"other_name": "",
|
1959 |
+
"required_fields": []
|
1960 |
+
},
|
1961 |
+
{
|
1962 |
+
"slug": "gls",
|
1963 |
+
"name": "GLS",
|
1964 |
+
"other_name": "General Logistics Systems",
|
1965 |
+
"required_fields": []
|
1966 |
+
},
|
1967 |
+
{
|
1968 |
+
"slug": "gls-croatia",
|
1969 |
+
"name": "GLS Croatia",
|
1970 |
+
"other_name": "",
|
1971 |
+
"required_fields": []
|
1972 |
+
},
|
1973 |
+
{
|
1974 |
+
"slug": "gls-cz",
|
1975 |
+
"name": "GLS Czech Republic",
|
1976 |
+
"other_name": "",
|
1977 |
+
"required_fields": []
|
1978 |
+
},
|
1979 |
+
{
|
1980 |
+
"slug": "gls-da",
|
1981 |
+
"name": "GLS Denmark",
|
1982 |
+
"other_name": null,
|
1983 |
+
"required_fields": []
|
1984 |
+
},
|
1985 |
+
{
|
1986 |
+
"slug": "gls-italy",
|
1987 |
+
"name": "GLS Italy",
|
1988 |
+
"other_name": "GLS Corriere Espresso",
|
1989 |
+
"required_fields": []
|
1990 |
+
},
|
1991 |
+
{
|
1992 |
+
"slug": "gls-netherlands",
|
1993 |
+
"name": "GLS Netherlands",
|
1994 |
+
"other_name": "GLS NL",
|
1995 |
+
"required_fields": [
|
1996 |
+
"tracking_postal_code"
|
1997 |
+
]
|
1998 |
+
},
|
1999 |
+
{
|
2000 |
+
"slug": "gls-slovakia",
|
2001 |
+
"name": "GLS General Logistics Systems Slovakia s.r.o.",
|
2002 |
+
"other_name": "",
|
2003 |
+
"required_fields": []
|
2004 |
+
},
|
2005 |
+
{
|
2006 |
+
"slug": "gls-slovenia",
|
2007 |
+
"name": "GLS Slovenia",
|
2008 |
+
"other_name": "",
|
2009 |
+
"required_fields": []
|
2010 |
+
},
|
2011 |
+
{
|
2012 |
+
"slug": "gls-spain",
|
2013 |
+
"name": "GLS Spain",
|
2014 |
+
"other_name": "",
|
2015 |
+
"required_fields": [
|
2016 |
+
"tracking_key"
|
2017 |
+
]
|
2018 |
+
},
|
2019 |
+
{
|
2020 |
+
"slug": "gofly",
|
2021 |
+
"name": "GoFly",
|
2022 |
+
"other_name": "GoFlyi",
|
2023 |
+
"required_fields": []
|
2024 |
+
},
|
2025 |
+
{
|
2026 |
+
"slug": "gojavas",
|
2027 |
+
"name": "GoJavas",
|
2028 |
+
"other_name": "Javas",
|
2029 |
+
"required_fields": []
|
2030 |
+
},
|
2031 |
+
{
|
2032 |
+
"slug": "grab-webhook",
|
2033 |
+
"name": "Grab",
|
2034 |
+
"other_name": null,
|
2035 |
+
"required_fields": []
|
2036 |
+
},
|
2037 |
+
{
|
2038 |
+
"slug": "greyhound",
|
2039 |
+
"name": "Greyhound",
|
2040 |
+
"other_name": "Greyhound Package Express",
|
2041 |
+
"required_fields": []
|
2042 |
+
},
|
2043 |
+
{
|
2044 |
+
"slug": "gsi-express",
|
2045 |
+
"name": "GSI EXPRESS",
|
2046 |
+
"other_name": "",
|
2047 |
+
"required_fields": []
|
2048 |
+
},
|
2049 |
+
{
|
2050 |
+
"slug": "gso",
|
2051 |
+
"name": "GSO(GLS-USA)",
|
2052 |
+
"other_name": "GSO Freight",
|
2053 |
+
"required_fields": []
|
2054 |
+
},
|
2055 |
+
{
|
2056 |
+
"slug": "hct-logistics",
|
2057 |
+
"name": "HCT LOGISTICS CO.LTD.",
|
2058 |
+
"other_name": "",
|
2059 |
+
"required_fields": []
|
2060 |
+
},
|
2061 |
+
{
|
2062 |
+
"slug": "hdb",
|
2063 |
+
"name": "Haidaibao",
|
2064 |
+
"other_name": "",
|
2065 |
+
"required_fields": []
|
2066 |
+
},
|
2067 |
+
{
|
2068 |
+
"slug": "hdb-box",
|
2069 |
+
"name": "Haidaibao (BOX)",
|
2070 |
+
"other_name": "",
|
2071 |
+
"required_fields": []
|
2072 |
+
},
|
2073 |
+
{
|
2074 |
+
"slug": "helthjem",
|
2075 |
+
"name": "Helthjem",
|
2076 |
+
"other_name": null,
|
2077 |
+
"required_fields": []
|
2078 |
+
},
|
2079 |
+
{
|
2080 |
+
"slug": "hermes",
|
2081 |
+
"name": "Hermesworld",
|
2082 |
+
"other_name": "Hermes-europe UK",
|
2083 |
+
"required_fields": []
|
2084 |
+
},
|
2085 |
+
{
|
2086 |
+
"slug": "hermes-de",
|
2087 |
+
"name": "Hermes Germany",
|
2088 |
+
"other_name": "myhermes.de, Hermes Logistik Gruppe Deutschland",
|
2089 |
+
"required_fields": []
|
2090 |
+
},
|
2091 |
+
{
|
2092 |
+
"slug": "hermes-it",
|
2093 |
+
"name": "Hermes Italy",
|
2094 |
+
"other_name": "",
|
2095 |
+
"required_fields": []
|
2096 |
+
},
|
2097 |
+
{
|
2098 |
+
"slug": "hh-exp",
|
2099 |
+
"name": "Hua Han Logistics",
|
2100 |
+
"other_name": "u534eu7ff0u56fdu9645u7269u6d41",
|
2101 |
+
"required_fields": []
|
2102 |
+
},
|
2103 |
+
{
|
2104 |
+
"slug": "hipshipper",
|
2105 |
+
"name": "Hipshipper",
|
2106 |
+
"other_name": "",
|
2107 |
+
"required_fields": []
|
2108 |
+
},
|
2109 |
+
{
|
2110 |
+
"slug": "holisol",
|
2111 |
+
"name": "Holisol",
|
2112 |
+
"other_name": "",
|
2113 |
+
"required_fields": []
|
2114 |
+
},
|
2115 |
+
{
|
2116 |
+
"slug": "home-delivery-solutions",
|
2117 |
+
"name": "Home Delivery Solutions Ltd",
|
2118 |
+
"other_name": null,
|
2119 |
+
"required_fields": []
|
2120 |
+
},
|
2121 |
+
{
|
2122 |
+
"slug": "homelogistics",
|
2123 |
+
"name": "Home Logistics",
|
2124 |
+
"other_name": null,
|
2125 |
+
"required_fields": []
|
2126 |
+
},
|
2127 |
+
{
|
2128 |
+
"slug": "hong-kong-post",
|
2129 |
+
"name": "Hong Kong Post",
|
2130 |
+
"other_name": "香港郵政",
|
2131 |
+
"required_fields": []
|
2132 |
+
},
|
2133 |
+
{
|
2134 |
+
"slug": "hrvatska-posta",
|
2135 |
+
"name": "Hrvatska Pošta",
|
2136 |
+
"other_name": "Croatia Post",
|
2137 |
+
"required_fields": []
|
2138 |
+
},
|
2139 |
+
{
|
2140 |
+
"slug": "hsm-global",
|
2141 |
+
"name": "HSM Global",
|
2142 |
+
"other_name": null,
|
2143 |
+
"required_fields": []
|
2144 |
+
},
|
2145 |
+
{
|
2146 |
+
"slug": "hunter-express",
|
2147 |
+
"name": "Hunter Express",
|
2148 |
+
"other_name": "",
|
2149 |
+
"required_fields": []
|
2150 |
+
},
|
2151 |
+
{
|
2152 |
+
"slug": "huodull",
|
2153 |
+
"name": "Huodull",
|
2154 |
+
"other_name": "货兜",
|
2155 |
+
"required_fields": []
|
2156 |
+
},
|
2157 |
+
{
|
2158 |
+
"slug": "hx-express",
|
2159 |
+
"name": "HX Express",
|
2160 |
+
"other_name": "",
|
2161 |
+
"required_fields": []
|
2162 |
+
},
|
2163 |
+
{
|
2164 |
+
"slug": "i-dika",
|
2165 |
+
"name": "i-dika",
|
2166 |
+
"other_name": "",
|
2167 |
+
"required_fields": []
|
2168 |
+
},
|
2169 |
+
{
|
2170 |
+
"slug": "i-parcel",
|
2171 |
+
"name": "i-parcel",
|
2172 |
+
"other_name": "iparcel",
|
2173 |
+
"required_fields": []
|
2174 |
+
},
|
2175 |
+
{
|
2176 |
+
"slug": "idexpress",
|
2177 |
+
"name": "IDEX",
|
2178 |
+
"other_name": "上海宏杉国际物流",
|
2179 |
+
"required_fields": []
|
2180 |
+
},
|
2181 |
+
{
|
2182 |
+
"slug": "ids-logistics",
|
2183 |
+
"name": "IDS Logistics",
|
2184 |
+
"other_name": "",
|
2185 |
+
"required_fields": []
|
2186 |
+
},
|
2187 |
+
{
|
2188 |
+
"slug": "imexglobalsolutions",
|
2189 |
+
"name": "IMEX Global Solutions",
|
2190 |
+
"other_name": "",
|
2191 |
+
"required_fields": []
|
2192 |
+
},
|
2193 |
+
{
|
2194 |
+
"slug": "iml",
|
2195 |
+
"name": "IML",
|
2196 |
+
"other_name": null,
|
2197 |
+
"required_fields": []
|
2198 |
+
},
|
2199 |
+
{
|
2200 |
+
"slug": "imxmail",
|
2201 |
+
"name": "IMX Mail",
|
2202 |
+
"other_name": "IMX International Mail Consolidator",
|
2203 |
+
"required_fields": []
|
2204 |
+
},
|
2205 |
+
{
|
2206 |
+
"slug": "india-post",
|
2207 |
+
"name": "India Post Domestic",
|
2208 |
+
"other_name": "भारतीय डाक",
|
2209 |
+
"required_fields": []
|
2210 |
+
},
|
2211 |
+
{
|
2212 |
+
"slug": "india-post-int",
|
2213 |
+
"name": "India Post International",
|
2214 |
+
"other_name": "भारतीय डाक, Speed Post & eMO, EMS, IPS Web",
|
2215 |
+
"required_fields": []
|
2216 |
+
},
|
2217 |
+
{
|
2218 |
+
"slug": "inexpost",
|
2219 |
+
"name": "Inexpost",
|
2220 |
+
"other_name": "",
|
2221 |
+
"required_fields": []
|
2222 |
+
},
|
2223 |
+
{
|
2224 |
+
"slug": "inpost-paczkomaty",
|
2225 |
+
"name": "InPost Paczkomaty",
|
2226 |
+
"other_name": "",
|
2227 |
+
"required_fields": []
|
2228 |
+
},
|
2229 |
+
{
|
2230 |
+
"slug": "intel-valley",
|
2231 |
+
"name": "Intel-Valley Supply chain (ShenZhen) Co. Ltd",
|
2232 |
+
"other_name": "智谷供应链(深圳)有限公司",
|
2233 |
+
"required_fields": []
|
2234 |
+
},
|
2235 |
+
{
|
2236 |
+
"slug": "intelipost",
|
2237 |
+
"name": "Intelipost (TMS for LATAM)",
|
2238 |
+
"other_name": "",
|
2239 |
+
"required_fields": []
|
2240 |
+
},
|
2241 |
+
{
|
2242 |
+
"slug": "interlink-express",
|
2243 |
+
"name": "DPD Local",
|
2244 |
+
"other_name": "Interlink UK",
|
2245 |
+
"required_fields": []
|
2246 |
+
},
|
2247 |
+
{
|
2248 |
+
"slug": "interlink-express-reference",
|
2249 |
+
"name": "DPD Local reference",
|
2250 |
+
"other_name": "",
|
2251 |
+
"required_fields": [
|
2252 |
+
"tracking_postal_code"
|
2253 |
+
]
|
2254 |
+
},
|
2255 |
+
{
|
2256 |
+
"slug": "international-seur",
|
2257 |
+
"name": "International Seur",
|
2258 |
+
"other_name": "SEUR Internacional",
|
2259 |
+
"required_fields": []
|
2260 |
+
},
|
2261 |
+
{
|
2262 |
+
"slug": "international-seur-api",
|
2263 |
+
"name": "International Seur API",
|
2264 |
+
"other_name": null,
|
2265 |
+
"required_fields": [
|
2266 |
+
"tracking_ship_date"
|
2267 |
+
]
|
2268 |
+
},
|
2269 |
+
{
|
2270 |
+
"slug": "interparcel-au",
|
2271 |
+
"name": "Interparcel Australia",
|
2272 |
+
"other_name": "Interparcel",
|
2273 |
+
"required_fields": []
|
2274 |
+
},
|
2275 |
+
{
|
2276 |
+
"slug": "interparcel-nz",
|
2277 |
+
"name": "Interparcel New Zealand",
|
2278 |
+
"other_name": "Interparcel",
|
2279 |
+
"required_fields": []
|
2280 |
+
},
|
2281 |
+
{
|
2282 |
+
"slug": "interparcel-uk",
|
2283 |
+
"name": "Interparcel UK",
|
2284 |
+
"other_name": "Interparcel",
|
2285 |
+
"required_fields": []
|
2286 |
+
},
|
2287 |
+
{
|
2288 |
+
"slug": "intexpress",
|
2289 |
+
"name": "Internet Express",
|
2290 |
+
"other_name": "",
|
2291 |
+
"required_fields": []
|
2292 |
+
},
|
2293 |
+
{
|
2294 |
+
"slug": "israel-post",
|
2295 |
+
"name": "Israel Post",
|
2296 |
+
"other_name": "חברת דואר ישראל",
|
2297 |
+
"required_fields": []
|
2298 |
+
},
|
2299 |
+
{
|
2300 |
+
"slug": "israel-post-domestic",
|
2301 |
+
"name": "Israel Post Domestic",
|
2302 |
+
"other_name": "חברת דואר ישראל מקומית",
|
2303 |
+
"required_fields": []
|
2304 |
+
},
|
2305 |
+
{
|
2306 |
+
"slug": "italy-sda",
|
2307 |
+
"name": "Italy SDA",
|
2308 |
+
"other_name": "SDA Express Courier",
|
2309 |
+
"required_fields": []
|
2310 |
+
},
|
2311 |
+
{
|
2312 |
+
"slug": "ivoy-webhook",
|
2313 |
+
"name": "Ivoy",
|
2314 |
+
"other_name": "",
|
2315 |
+
"required_fields": []
|
2316 |
+
},
|
2317 |
+
{
|
2318 |
+
"slug": "j-net",
|
2319 |
+
"name": "J-Net",
|
2320 |
+
"other_name": "",
|
2321 |
+
"required_fields": []
|
2322 |
+
},
|
2323 |
+
{
|
2324 |
+
"slug": "jam-express",
|
2325 |
+
"name": "Jam Express",
|
2326 |
+
"other_name": "JAM Global Express",
|
2327 |
+
"required_fields": []
|
2328 |
+
},
|
2329 |
+
{
|
2330 |
+
"slug": "janco",
|
2331 |
+
"name": "Janco Ecommerce",
|
2332 |
+
"other_name": "",
|
2333 |
+
"required_fields": []
|
2334 |
+
},
|
2335 |
+
{
|
2336 |
+
"slug": "janio",
|
2337 |
+
"name": "Janio Asia",
|
2338 |
+
"other_name": "",
|
2339 |
+
"required_fields": []
|
2340 |
+
},
|
2341 |
+
{
|
2342 |
+
"slug": "japan-post",
|
2343 |
+
"name": "Japan Post",
|
2344 |
+
"other_name": "日本郵便",
|
2345 |
+
"required_fields": []
|
2346 |
+
},
|
2347 |
+
{
|
2348 |
+
"slug": "jayonexpress",
|
2349 |
+
"name": "Jayon Express (JEX)",
|
2350 |
+
"other_name": "",
|
2351 |
+
"required_fields": []
|
2352 |
+
},
|
2353 |
+
{
|
2354 |
+
"slug": "jcex",
|
2355 |
+
"name": "JCEX",
|
2356 |
+
"other_name": "JiaCheng, 杭州佳成",
|
2357 |
+
"required_fields": []
|
2358 |
+
},
|
2359 |
+
{
|
2360 |
+
"slug": "jersey-post",
|
2361 |
+
"name": "Jersey Post",
|
2362 |
+
"other_name": "",
|
2363 |
+
"required_fields": []
|
2364 |
+
},
|
2365 |
+
{
|
2366 |
+
"slug": "jet-ship",
|
2367 |
+
"name": "Jet-Ship Worldwide",
|
2368 |
+
"other_name": "",
|
2369 |
+
"required_fields": []
|
2370 |
+
},
|
2371 |
+
{
|
2372 |
+
"slug": "jindouyun",
|
2373 |
+
"name": "金斗云物流",
|
2374 |
+
"other_name": "JINDOUYUN LOGISTICS",
|
2375 |
+
"required_fields": []
|
2376 |
+
},
|
2377 |
+
{
|
2378 |
+
"slug": "jinsung",
|
2379 |
+
"name": "JINSUNG TRADING",
|
2380 |
+
"other_name": "",
|
2381 |
+
"required_fields": []
|
2382 |
+
},
|
2383 |
+
{
|
2384 |
+
"slug": "jne",
|
2385 |
+
"name": "JNE",
|
2386 |
+
"other_name": "Express Across Nation, Tiki Jalur Nugraha Ekakurir",
|
2387 |
+
"required_fields": []
|
2388 |
+
},
|
2389 |
+
{
|
2390 |
+
"slug": "jne-api",
|
2391 |
+
"name": "JNE (API)",
|
2392 |
+
"other_name": "",
|
2393 |
+
"required_fields": []
|
2394 |
+
},
|
2395 |
+
{
|
2396 |
+
"slug": "jocom",
|
2397 |
+
"name": "Jocom",
|
2398 |
+
"other_name": "",
|
2399 |
+
"required_fields": []
|
2400 |
+
},
|
2401 |
+
{
|
2402 |
+
"slug": "jtexpress",
|
2403 |
+
"name": "J&T EXPRESS MALAYSIA",
|
2404 |
+
"other_name": "",
|
2405 |
+
"required_fields": []
|
2406 |
+
},
|
2407 |
+
{
|
2408 |
+
"slug": "jx",
|
2409 |
+
"name": "JX",
|
2410 |
+
"other_name": "",
|
2411 |
+
"required_fields": []
|
2412 |
+
},
|
2413 |
+
{
|
2414 |
+
"slug": "k1-express",
|
2415 |
+
"name": "K1 Express",
|
2416 |
+
"other_name": "",
|
2417 |
+
"required_fields": []
|
2418 |
+
},
|
2419 |
+
{
|
2420 |
+
"slug": "kangaroo-my",
|
2421 |
+
"name": "Kangaroo Worldwide Express",
|
2422 |
+
"other_name": "",
|
2423 |
+
"required_fields": []
|
2424 |
+
},
|
2425 |
+
{
|
2426 |
+
"slug": "kec",
|
2427 |
+
"name": "KEC",
|
2428 |
+
"other_name": "",
|
2429 |
+
"required_fields": []
|
2430 |
+
},
|
2431 |
+
{
|
2432 |
+
"slug": "kerry-ecommerce",
|
2433 |
+
"name": "Kerry eCommerce",
|
2434 |
+
"other_name": "",
|
2435 |
+
"required_fields": []
|
2436 |
+
},
|
2437 |
+
{
|
2438 |
+
"slug": "kerry-logistics",
|
2439 |
+
"name": "Kerry Express Thailand",
|
2440 |
+
"other_name": "嘉里物流, Kerry Logistics",
|
2441 |
+
"required_fields": []
|
2442 |
+
},
|
2443 |
+
{
|
2444 |
+
"slug": "kerrytj",
|
2445 |
+
"name": "Kerry TJ Logistics",
|
2446 |
+
"other_name": "KTJ嘉里大榮物流",
|
2447 |
+
"required_fields": []
|
2448 |
+
},
|
2449 |
+
{
|
2450 |
+
"slug": "kerryttc-vn",
|
2451 |
+
"name": "Kerry Express (Vietnam) Co Ltd",
|
2452 |
+
"other_name": "KTTC",
|
2453 |
+
"required_fields": []
|
2454 |
+
},
|
2455 |
+
{
|
2456 |
+
"slug": "kgmhub",
|
2457 |
+
"name": "KGM Hub",
|
2458 |
+
"other_name": "KGM",
|
2459 |
+
"required_fields": []
|
2460 |
+
},
|
2461 |
+
{
|
2462 |
+
"slug": "kiala",
|
2463 |
+
"name": "Kiala",
|
2464 |
+
"other_name": "",
|
2465 |
+
"required_fields": []
|
2466 |
+
},
|
2467 |
+
{
|
2468 |
+
"slug": "kn",
|
2469 |
+
"name": "Kuehne + Nagel",
|
2470 |
+
"other_name": "KN",
|
2471 |
+
"required_fields": []
|
2472 |
+
},
|
2473 |
+
{
|
2474 |
+
"slug": "knuk",
|
2475 |
+
"name": "KNAirlink Aerospace Domestic Network",
|
2476 |
+
"other_name": "",
|
2477 |
+
"required_fields": []
|
2478 |
+
},
|
2479 |
+
{
|
2480 |
+
"slug": "korea-post",
|
2481 |
+
"name": "Korea Post EMS",
|
2482 |
+
"other_name": "우정사업본부",
|
2483 |
+
"required_fields": []
|
2484 |
+
},
|
2485 |
+
{
|
2486 |
+
"slug": "kpost",
|
2487 |
+
"name": "Korea Post",
|
2488 |
+
"other_name": "우정사업본부",
|
2489 |
+
"required_fields": []
|
2490 |
+
},
|
2491 |
+
{
|
2492 |
+
"slug": "kronos",
|
2493 |
+
"name": "Kronos Express",
|
2494 |
+
"other_name": "",
|
2495 |
+
"required_fields": []
|
2496 |
+
},
|
2497 |
+
{
|
2498 |
+
"slug": "kurasi",
|
2499 |
+
"name": "KURASI",
|
2500 |
+
"other_name": "",
|
2501 |
+
"required_fields": []
|
2502 |
+
},
|
2503 |
+
{
|
2504 |
+
"slug": "kwe-global",
|
2505 |
+
"name": "KWE Global",
|
2506 |
+
"other_name": "",
|
2507 |
+
"required_fields": []
|
2508 |
+
},
|
2509 |
+
{
|
2510 |
+
"slug": "kwt",
|
2511 |
+
"name": "Shenzhen Jinghuada Logistics Co., Ltd",
|
2512 |
+
"other_name": "KWT",
|
2513 |
+
"required_fields": []
|
2514 |
+
},
|
2515 |
+
{
|
2516 |
+
"slug": "ky-express",
|
2517 |
+
"name": "Kua Yue Express",
|
2518 |
+
"other_name": "KYE",
|
2519 |
+
"required_fields": []
|
2520 |
+
},
|
2521 |
+
{
|
2522 |
+
"slug": "la-poste-colissimo",
|
2523 |
+
"name": "La Poste",
|
2524 |
+
"other_name": "Coliposte",
|
2525 |
+
"required_fields": []
|
2526 |
+
},
|
2527 |
+
{
|
2528 |
+
"slug": "lalamove",
|
2529 |
+
"name": "Lalamove",
|
2530 |
+
"other_name": "",
|
2531 |
+
"required_fields": []
|
2532 |
+
},
|
2533 |
+
{
|
2534 |
+
"slug": "landmark-global",
|
2535 |
+
"name": "Landmark Global",
|
2536 |
+
"other_name": "",
|
2537 |
+
"required_fields": []
|
2538 |
+
},
|
2539 |
+
{
|
2540 |
+
"slug": "landmark-global-reference",
|
2541 |
+
"name": "Landmark Global Reference",
|
2542 |
+
"other_name": "",
|
2543 |
+
"required_fields": []
|
2544 |
+
},
|
2545 |
+
{
|
2546 |
+
"slug": "lao-post",
|
2547 |
+
"name": "Lao Post",
|
2548 |
+
"other_name": "Laos Postal Service",
|
2549 |
+
"required_fields": []
|
2550 |
+
},
|
2551 |
+
{
|
2552 |
+
"slug": "lasership",
|
2553 |
+
"name": "LaserShip",
|
2554 |
+
"other_name": "LaserShip",
|
2555 |
+
"required_fields": []
|
2556 |
+
},
|
2557 |
+
{
|
2558 |
+
"slug": "latvijas-pasts",
|
2559 |
+
"name": "Latvijas Pasts",
|
2560 |
+
"other_name": "Latvijas Pasts",
|
2561 |
+
"required_fields": []
|
2562 |
+
},
|
2563 |
+
{
|
2564 |
+
"slug": "leader",
|
2565 |
+
"name": "leader",
|
2566 |
+
"other_name": "立德国际物流",
|
2567 |
+
"required_fields": []
|
2568 |
+
},
|
2569 |
+
{
|
2570 |
+
"slug": "legion-express",
|
2571 |
+
"name": "Legion Express",
|
2572 |
+
"other_name": "",
|
2573 |
+
"required_fields": []
|
2574 |
+
},
|
2575 |
+
{
|
2576 |
+
"slug": "lexship",
|
2577 |
+
"name": "LexShip",
|
2578 |
+
"other_name": "",
|
2579 |
+
"required_fields": []
|
2580 |
+
},
|
2581 |
+
{
|
2582 |
+
"slug": "lht-express",
|
2583 |
+
"name": "LHT Express",
|
2584 |
+
"other_name": "",
|
2585 |
+
"required_fields": []
|
2586 |
+
},
|
2587 |
+
{
|
2588 |
+
"slug": "liefery",
|
2589 |
+
"name": "liefery",
|
2590 |
+
"other_name": "",
|
2591 |
+
"required_fields": []
|
2592 |
+
},
|
2593 |
+
{
|
2594 |
+
"slug": "lietuvos-pastas",
|
2595 |
+
"name": "Lietuvos Paštas",
|
2596 |
+
"other_name": "Lithuania Post, LP Express",
|
2597 |
+
"required_fields": []
|
2598 |
+
},
|
2599 |
+
{
|
2600 |
+
"slug": "line",
|
2601 |
+
"name": "Line Clear Express & Logistics Sdn Bhd",
|
2602 |
+
"other_name": "",
|
2603 |
+
"required_fields": []
|
2604 |
+
},
|
2605 |
+
{
|
2606 |
+
"slug": "linkbridge",
|
2607 |
+
"name": "Link Bridge(BeiJing)international logistics co.,ltd",
|
2608 |
+
"other_name": "联博瑞翔(北京)国际物流股份有限公司",
|
2609 |
+
"required_fields": []
|
2610 |
+
},
|
2611 |
+
{
|
2612 |
+
"slug": "lion-parcel",
|
2613 |
+
"name": "Lion Parcel",
|
2614 |
+
"other_name": "",
|
2615 |
+
"required_fields": []
|
2616 |
+
},
|
2617 |
+
{
|
2618 |
+
"slug": "livrapide",
|
2619 |
+
"name": "Livrapide",
|
2620 |
+
"other_name": "",
|
2621 |
+
"required_fields": []
|
2622 |
+
},
|
2623 |
+
{
|
2624 |
+
"slug": "locus-webhook",
|
2625 |
+
"name": "Locus",
|
2626 |
+
"other_name": "",
|
2627 |
+
"required_fields": []
|
2628 |
+
},
|
2629 |
+
{
|
2630 |
+
"slug": "logistyx-transgroup",
|
2631 |
+
"name": "Transgroup",
|
2632 |
+
"other_name": "",
|
2633 |
+
"required_fields": []
|
2634 |
+
},
|
2635 |
+
{
|
2636 |
+
"slug": "logwin-logistics",
|
2637 |
+
"name": "Logwin Logistics",
|
2638 |
+
"other_name": "",
|
2639 |
+
"required_fields": []
|
2640 |
+
},
|
2641 |
+
{
|
2642 |
+
"slug": "lonestar",
|
2643 |
+
"name": "Lone Star Overnight",
|
2644 |
+
"other_name": "",
|
2645 |
+
"required_fields": []
|
2646 |
+
},
|
2647 |
+
{
|
2648 |
+
"slug": "loomis-express",
|
2649 |
+
"name": "Loomis Express",
|
2650 |
+
"other_name": "",
|
2651 |
+
"required_fields": []
|
2652 |
+
},
|
2653 |
+
{
|
2654 |
+
"slug": "lotte",
|
2655 |
+
"name": "Lotte Global Logistics",
|
2656 |
+
"other_name": "",
|
2657 |
+
"required_fields": []
|
2658 |
+
},
|
2659 |
+
{
|
2660 |
+
"slug": "ltianexp",
|
2661 |
+
"name": "LTIAN EXP",
|
2662 |
+
"other_name": "乐天国际",
|
2663 |
+
"required_fields": []
|
2664 |
+
},
|
2665 |
+
{
|
2666 |
+
"slug": "ltl",
|
2667 |
+
"name": "LTL",
|
2668 |
+
"other_name": "",
|
2669 |
+
"required_fields": []
|
2670 |
+
},
|
2671 |
+
{
|
2672 |
+
"slug": "lwe-hk",
|
2673 |
+
"name": "Logistic Worldwide Express",
|
2674 |
+
"other_name": "LWE",
|
2675 |
+
"required_fields": []
|
2676 |
+
},
|
2677 |
+
{
|
2678 |
+
"slug": "m-xpress",
|
2679 |
+
"name": "M Xpress Sdn Bhd",
|
2680 |
+
"other_name": "",
|
2681 |
+
"required_fields": []
|
2682 |
+
},
|
2683 |
+
{
|
2684 |
+
"slug": "magyar-posta",
|
2685 |
+
"name": "Magyar Posta",
|
2686 |
+
"other_name": "Hungarian Post",
|
2687 |
+
"required_fields": []
|
2688 |
+
},
|
2689 |
+
{
|
2690 |
+
"slug": "mail-box-etc",
|
2691 |
+
"name": "Mail Boxes Etc.",
|
2692 |
+
"other_name": "",
|
2693 |
+
"required_fields": []
|
2694 |
+
},
|
2695 |
+
{
|
2696 |
+
"slug": "mailamericas",
|
2697 |
+
"name": "MailAmericas",
|
2698 |
+
"other_name": "",
|
2699 |
+
"required_fields": []
|
2700 |
+
},
|
2701 |
+
{
|
2702 |
+
"slug": "mailplus",
|
2703 |
+
"name": "MailPlus",
|
2704 |
+
"other_name": "",
|
2705 |
+
"required_fields": []
|
2706 |
+
},
|
2707 |
+
{
|
2708 |
+
"slug": "mailplus-jp",
|
2709 |
+
"name": "MailPlus (Japan)",
|
2710 |
+
"other_name": "",
|
2711 |
+
"required_fields": []
|
2712 |
+
},
|
2713 |
+
{
|
2714 |
+
"slug": "mainfreight",
|
2715 |
+
"name": "Mainfreight",
|
2716 |
+
"other_name": "",
|
2717 |
+
"required_fields": []
|
2718 |
+
},
|
2719 |
+
{
|
2720 |
+
"slug": "mainway",
|
2721 |
+
"name": "Mainway",
|
2722 |
+
"other_name": "",
|
2723 |
+
"required_fields": []
|
2724 |
+
},
|
2725 |
+
{
|
2726 |
+
"slug": "malaysia-post",
|
2727 |
+
"name": "Malaysia Post EMS / Pos Laju",
|
2728 |
+
"other_name": "Pos Ekspres, Pos Malaysia Express",
|
2729 |
+
"required_fields": []
|
2730 |
+
},
|
2731 |
+
{
|
2732 |
+
"slug": "malaysia-post-posdaftar",
|
2733 |
+
"name": "Malaysia Post - Registered",
|
2734 |
+
"other_name": "PosDaftar",
|
2735 |
+
"required_fields": []
|
2736 |
+
},
|
2737 |
+
{
|
2738 |
+
"slug": "mara-xpress",
|
2739 |
+
"name": "Mara Xpress",
|
2740 |
+
"other_name": "",
|
2741 |
+
"required_fields": []
|
2742 |
+
},
|
2743 |
+
{
|
2744 |
+
"slug": "matdespatch",
|
2745 |
+
"name": "Matdespatch",
|
2746 |
+
"other_name": "",
|
2747 |
+
"required_fields": []
|
2748 |
+
},
|
2749 |
+
{
|
2750 |
+
"slug": "matkahuolto",
|
2751 |
+
"name": "Matkahuolto",
|
2752 |
+
"other_name": "Oy Matkahuolto Ab",
|
2753 |
+
"required_fields": []
|
2754 |
+
},
|
2755 |
+
{
|
2756 |
+
"slug": "mazet",
|
2757 |
+
"name": "Groupe Mazet",
|
2758 |
+
"other_name": "",
|
2759 |
+
"required_fields": []
|
2760 |
+
},
|
2761 |
+
{
|
2762 |
+
"slug": "megasave",
|
2763 |
+
"name": "Megasave",
|
2764 |
+
"other_name": "",
|
2765 |
+
"required_fields": []
|
2766 |
+
},
|
2767 |
+
{
|
2768 |
+
"slug": "mexico-redpack",
|
2769 |
+
"name": "Mexico Redpack",
|
2770 |
+
"other_name": "TNT Mexico",
|
2771 |
+
"required_fields": []
|
2772 |
+
},
|
2773 |
+
{
|
2774 |
+
"slug": "mexico-senda-express",
|
2775 |
+
"name": "Mexico Senda Express",
|
2776 |
+
"other_name": "Mexico Senda Express",
|
2777 |
+
"required_fields": []
|
2778 |
+
},
|
2779 |
+
{
|
2780 |
+
"slug": "mglobal",
|
2781 |
+
"name": "PT MGLOBAL LOGISTICS INDONESIA",
|
2782 |
+
"other_name": "",
|
2783 |
+
"required_fields": []
|
2784 |
+
},
|
2785 |
+
{
|
2786 |
+
"slug": "midland",
|
2787 |
+
"name": "Midland",
|
2788 |
+
"other_name": "",
|
2789 |
+
"required_fields": []
|
2790 |
+
},
|
2791 |
+
{
|
2792 |
+
"slug": "mikropakket",
|
2793 |
+
"name": "Mikropakket",
|
2794 |
+
"other_name": "",
|
2795 |
+
"required_fields": [
|
2796 |
+
"tracking_postal_code"
|
2797 |
+
]
|
2798 |
+
},
|
2799 |
+
{
|
2800 |
+
"slug": "mikropakket-be",
|
2801 |
+
"name": "Mikropakket Belgium",
|
2802 |
+
"other_name": "",
|
2803 |
+
"required_fields": [
|
2804 |
+
"tracking_postal_code"
|
2805 |
+
]
|
2806 |
+
},
|
2807 |
+
{
|
2808 |
+
"slug": "milkman",
|
2809 |
+
"name": "Milkman",
|
2810 |
+
"other_name": "",
|
2811 |
+
"required_fields": []
|
2812 |
+
},
|
2813 |
+
{
|
2814 |
+
"slug": "misumi-cn",
|
2815 |
+
"name": "MISUMI Group Inc.",
|
2816 |
+
"other_name": "",
|
2817 |
+
"required_fields": []
|
2818 |
+
},
|
2819 |
+
{
|
2820 |
+
"slug": "mondialrelay",
|
2821 |
+
"name": "Mondial Relay",
|
2822 |
+
"other_name": "Mondial Relay France",
|
2823 |
+
"required_fields": [
|
2824 |
+
"tracking_postal_code"
|
2825 |
+
]
|
2826 |
+
},
|
2827 |
+
{
|
2828 |
+
"slug": "mondialrelay-es",
|
2829 |
+
"name": "Mondial Relay Spain(Punto Pack)",
|
2830 |
+
"other_name": null,
|
2831 |
+
"required_fields": []
|
2832 |
+
},
|
2833 |
+
{
|
2834 |
+
"slug": "mondialrelay-fr",
|
2835 |
+
"name": "Mondial Relay France",
|
2836 |
+
"other_name": null,
|
2837 |
+
"required_fields": []
|
2838 |
+
},
|
2839 |
+
{
|
2840 |
+
"slug": "mrw-spain",
|
2841 |
+
"name": "MRW",
|
2842 |
+
"other_name": "MRW Spain",
|
2843 |
+
"required_fields": []
|
2844 |
+
},
|
2845 |
+
{
|
2846 |
+
"slug": "mudita",
|
2847 |
+
"name": "MUDITA",
|
2848 |
+
"other_name": "",
|
2849 |
+
"required_fields": []
|
2850 |
+
},
|
2851 |
+
{
|
2852 |
+
"slug": "mx-cargo",
|
2853 |
+
"name": "M&X cargo",
|
2854 |
+
"other_name": "M&X International Shipping Agency Co.,LTD",
|
2855 |
+
"required_fields": []
|
2856 |
+
},
|
2857 |
+
{
|
2858 |
+
"slug": "mxe",
|
2859 |
+
"name": "MXE Express",
|
2860 |
+
"other_name": "上海淼信货运代理有限公司",
|
2861 |
+
"required_fields": []
|
2862 |
+
},
|
2863 |
+
{
|
2864 |
+
"slug": "myhermes-uk",
|
2865 |
+
"name": "MyHermes UK",
|
2866 |
+
"other_name": "",
|
2867 |
+
"required_fields": []
|
2868 |
+
},
|
2869 |
+
{
|
2870 |
+
"slug": "mypostonline",
|
2871 |
+
"name": "Mypostonline",
|
2872 |
+
"other_name": "MYBOXPOST",
|
2873 |
+
"required_fields": []
|
2874 |
+
},
|
2875 |
+
{
|
2876 |
+
"slug": "nacex",
|
2877 |
+
"name": "NACEX",
|
2878 |
+
"other_name": "",
|
2879 |
+
"required_fields": [
|
2880 |
+
"tracking_account_number"
|
2881 |
+
]
|
2882 |
+
},
|
2883 |
+
{
|
2884 |
+
"slug": "nacex-spain",
|
2885 |
+
"name": "NACEX Spain",
|
2886 |
+
"other_name": "NACEX Logista",
|
2887 |
+
"required_fields": [
|
2888 |
+
"tracking_postal_code"
|
2889 |
+
]
|
2890 |
+
},
|
2891 |
+
{
|
2892 |
+
"slug": "nanjingwoyuan",
|
2893 |
+
"name": "Nanjing Woyuan",
|
2894 |
+
"other_name": "u6c83u6e90",
|
2895 |
+
"required_fields": []
|
2896 |
+
},
|
2897 |
+
{
|
2898 |
+
"slug": "naqel-express",
|
2899 |
+
"name": "Naqel Express",
|
2900 |
+
"other_name": "",
|
2901 |
+
"required_fields": []
|
2902 |
+
},
|
2903 |
+
{
|
2904 |
+
"slug": "national-sameday",
|
2905 |
+
"name": "National Sameday",
|
2906 |
+
"other_name": "",
|
2907 |
+
"required_fields": []
|
2908 |
+
},
|
2909 |
+
{
|
2910 |
+
"slug": "nationwide-my",
|
2911 |
+
"name": "Nationwide Express",
|
2912 |
+
"other_name": "nationwide2u",
|
2913 |
+
"required_fields": []
|
2914 |
+
},
|
2915 |
+
{
|
2916 |
+
"slug": "new-zealand-post",
|
2917 |
+
"name": "New Zealand Post",
|
2918 |
+
"other_name": "NZ Post",
|
2919 |
+
"required_fields": []
|
2920 |
+
},
|
2921 |
+
{
|
2922 |
+
"slug": "neway",
|
2923 |
+
"name": "Neway Transport",
|
2924 |
+
"other_name": "",
|
2925 |
+
"required_fields": []
|
2926 |
+
},
|
2927 |
+
{
|
2928 |
+
"slug": "newgistics",
|
2929 |
+
"name": "Newgistics",
|
2930 |
+
"other_name": "",
|
2931 |
+
"required_fields": []
|
2932 |
+
},
|
2933 |
+
{
|
2934 |
+
"slug": "newgisticsapi",
|
2935 |
+
"name": "Newgistics API",
|
2936 |
+
"other_name": "",
|
2937 |
+
"required_fields": []
|
2938 |
+
},
|
2939 |
+
{
|
2940 |
+
"slug": "newzealand-couriers",
|
2941 |
+
"name": "NEW ZEALAND COURIERS",
|
2942 |
+
"other_name": "",
|
2943 |
+
"required_fields": [
|
2944 |
+
"tracking_account_number"
|
2945 |
+
]
|
2946 |
+
},
|
2947 |
+
{
|
2948 |
+
"slug": "nhans-solutions",
|
2949 |
+
"name": "Nhans Solutions",
|
2950 |
+
"other_name": "Nhans Courier",
|
2951 |
+
"required_fields": []
|
2952 |
+
},
|
2953 |
+
{
|
2954 |
+
"slug": "nightline",
|
2955 |
+
"name": "Nightline",
|
2956 |
+
"other_name": "",
|
2957 |
+
"required_fields": []
|
2958 |
+
},
|
2959 |
+
{
|
2960 |
+
"slug": "nim-express",
|
2961 |
+
"name": "Nim Express",
|
2962 |
+
"other_name": "Armadillio Express",
|
2963 |
+
"required_fields": []
|
2964 |
+
},
|
2965 |
+
{
|
2966 |
+
"slug": "ninjavan",
|
2967 |
+
"name": "Ninja Van",
|
2968 |
+
"other_name": "",
|
2969 |
+
"required_fields": []
|
2970 |
+
},
|
2971 |
+
{
|
2972 |
+
"slug": "ninjavan-id",
|
2973 |
+
"name": "Ninja Van Indonesia",
|
2974 |
+
"other_name": "NinjaVan Indonesia",
|
2975 |
+
"required_fields": []
|
2976 |
+
},
|
2977 |
+
{
|
2978 |
+
"slug": "ninjavan-my",
|
2979 |
+
"name": "Ninja Van Malaysia",
|
2980 |
+
"other_name": "NinjaVan MY",
|
2981 |
+
"required_fields": []
|
2982 |
+
},
|
2983 |
+
{
|
2984 |
+
"slug": "ninjavan-philippines",
|
2985 |
+
"name": "Ninja Van Philippines",
|
2986 |
+
"other_name": "",
|
2987 |
+
"required_fields": []
|
2988 |
+
},
|
2989 |
+
{
|
2990 |
+
"slug": "ninjavan-thai",
|
2991 |
+
"name": "Ninja Van Thailand",
|
2992 |
+
"other_name": "",
|
2993 |
+
"required_fields": []
|
2994 |
+
},
|
2995 |
+
{
|
2996 |
+
"slug": "ninjavan-webhook",
|
2997 |
+
"name": "Ninjavan Webhook",
|
2998 |
+
"other_name": "",
|
2999 |
+
"required_fields": []
|
3000 |
+
},
|
3001 |
+
{
|
3002 |
+
"slug": "nipost",
|
3003 |
+
"name": "NiPost",
|
3004 |
+
"other_name": "Nigerian Postal Service",
|
3005 |
+
"required_fields": []
|
3006 |
+
},
|
3007 |
+
{
|
3008 |
+
"slug": "norsk-global",
|
3009 |
+
"name": "Norsk Global",
|
3010 |
+
"other_name": "Norsk European Wholesale",
|
3011 |
+
"required_fields": []
|
3012 |
+
},
|
3013 |
+
{
|
3014 |
+
"slug": "nova-poshta",
|
3015 |
+
"name": "Nova Poshta",
|
3016 |
+
"other_name": "Новая Почта",
|
3017 |
+
"required_fields": []
|
3018 |
+
},
|
3019 |
+
{
|
3020 |
+
"slug": "nova-poshtaint",
|
3021 |
+
"name": "Nova Poshta (International)",
|
3022 |
+
"other_name": "Новая Почта",
|
3023 |
+
"required_fields": []
|
3024 |
+
},
|
3025 |
+
{
|
3026 |
+
"slug": "nowlog-api",
|
3027 |
+
"name": "Sequoialog",
|
3028 |
+
"other_name": "",
|
3029 |
+
"required_fields": []
|
3030 |
+
},
|
3031 |
+
{
|
3032 |
+
"slug": "nox-nachtexpress",
|
3033 |
+
"name": "Innight Express Germany GmbH (nox NachtExpress)",
|
3034 |
+
"other_name": null,
|
3035 |
+
"required_fields": []
|
3036 |
+
},
|
3037 |
+
{
|
3038 |
+
"slug": "nox-night-time-express",
|
3039 |
+
"name": "NOX NightTimeExpress",
|
3040 |
+
"other_name": null,
|
3041 |
+
"required_fields": []
|
3042 |
+
},
|
3043 |
+
{
|
3044 |
+
"slug": "ntl",
|
3045 |
+
"name": "NTL logistics",
|
3046 |
+
"other_name": "",
|
3047 |
+
"required_fields": []
|
3048 |
+
},
|
3049 |
+
{
|
3050 |
+
"slug": "oca-ar",
|
3051 |
+
"name": "OCA Argentina",
|
3052 |
+
"other_name": "OCA e-Pak",
|
3053 |
+
"required_fields": []
|
3054 |
+
},
|
3055 |
+
{
|
3056 |
+
"slug": "ocs",
|
3057 |
+
"name": "OCS ANA Group",
|
3058 |
+
"other_name": "",
|
3059 |
+
"required_fields": []
|
3060 |
+
},
|
3061 |
+
{
|
3062 |
+
"slug": "ocs-worldwide",
|
3063 |
+
"name": "OCS WORLDWIDE",
|
3064 |
+
"other_name": "",
|
3065 |
+
"required_fields": []
|
3066 |
+
},
|
3067 |
+
{
|
3068 |
+
"slug": "okayparcel",
|
3069 |
+
"name": "OkayParcel",
|
3070 |
+
"other_name": "",
|
3071 |
+
"required_fields": []
|
3072 |
+
},
|
3073 |
+
{
|
3074 |
+
"slug": "old-dominion",
|
3075 |
+
"name": "Old Dominion Freight Line",
|
3076 |
+
"other_name": "ODFL",
|
3077 |
+
"required_fields": []
|
3078 |
+
},
|
3079 |
+
{
|
3080 |
+
"slug": "omniparcel",
|
3081 |
+
"name": "Omni Parcel",
|
3082 |
+
"other_name": "Omni-Channel Logistics (Seko)",
|
3083 |
+
"required_fields": []
|
3084 |
+
},
|
3085 |
+
{
|
3086 |
+
"slug": "omniva",
|
3087 |
+
"name": "Omniva",
|
3088 |
+
"other_name": "",
|
3089 |
+
"required_fields": []
|
3090 |
+
},
|
3091 |
+
{
|
3092 |
+
"slug": "oneclick",
|
3093 |
+
"name": "One click delivery services",
|
3094 |
+
"other_name": null,
|
3095 |
+
"required_fields": []
|
3096 |
+
},
|
3097 |
+
{
|
3098 |
+
"slug": "oneworldexpress",
|
3099 |
+
"name": "One World Express",
|
3100 |
+
"other_name": "u6613u65f6u9039u7269u6d41",
|
3101 |
+
"required_fields": []
|
3102 |
+
},
|
3103 |
+
{
|
3104 |
+
"slug": "ontrac",
|
3105 |
+
"name": "OnTrac",
|
3106 |
+
"other_name": "OnTrac Shipping",
|
3107 |
+
"required_fields": []
|
3108 |
+
},
|
3109 |
+
{
|
3110 |
+
"slug": "opek",
|
3111 |
+
"name": "FedEx Poland Domestic",
|
3112 |
+
"other_name": "OPEK",
|
3113 |
+
"required_fields": []
|
3114 |
+
},
|
3115 |
+
{
|
3116 |
+
"slug": "osm-worldwide",
|
3117 |
+
"name": "OSM Worldwide",
|
3118 |
+
"other_name": "",
|
3119 |
+
"required_fields": []
|
3120 |
+
},
|
3121 |
+
{
|
3122 |
+
"slug": "paack-webhook",
|
3123 |
+
"name": "Paack",
|
3124 |
+
"other_name": "",
|
3125 |
+
"required_fields": []
|
3126 |
+
},
|
3127 |
+
{
|
3128 |
+
"slug": "packlink",
|
3129 |
+
"name": "Packlink",
|
3130 |
+
"other_name": "Packlink Spain",
|
3131 |
+
"required_fields": []
|
3132 |
+
},
|
3133 |
+
{
|
3134 |
+
"slug": "packs",
|
3135 |
+
"name": "Packs",
|
3136 |
+
"other_name": null,
|
3137 |
+
"required_fields": [
|
3138 |
+
"tracking_postal_code"
|
3139 |
+
]
|
3140 |
+
},
|
3141 |
+
{
|
3142 |
+
"slug": "palexpress",
|
3143 |
+
"name": "PAL Express Limited",
|
3144 |
+
"other_name": "",
|
3145 |
+
"required_fields": []
|
3146 |
+
},
|
3147 |
+
{
|
3148 |
+
"slug": "palletways",
|
3149 |
+
"name": "Palletways",
|
3150 |
+
"other_name": "",
|
3151 |
+
"required_fields": [
|
3152 |
+
"tracking_postal_code"
|
3153 |
+
]
|
3154 |
+
},
|
3155 |
+
{
|
3156 |
+
"slug": "pan-asia",
|
3157 |
+
"name": "Pan-Asia International",
|
3158 |
+
"other_name": null,
|
3159 |
+
"required_fields": []
|
3160 |
+
},
|
3161 |
+
{
|
3162 |
+
"slug": "pandulogistics",
|
3163 |
+
"name": "Pandu Logistics",
|
3164 |
+
"other_name": "",
|
3165 |
+
"required_fields": []
|
3166 |
+
},
|
3167 |
+
{
|
3168 |
+
"slug": "panther",
|
3169 |
+
"name": "Panther",
|
3170 |
+
"other_name": "Panther Group UK",
|
3171 |
+
"required_fields": []
|
3172 |
+
},
|
3173 |
+
{
|
3174 |
+
"slug": "panther-order-number",
|
3175 |
+
"name": "Panther Order Number",
|
3176 |
+
"other_name": "Panther Group UK",
|
3177 |
+
"required_fields": [
|
3178 |
+
"tracking_postal_code"
|
3179 |
+
]
|
3180 |
+
},
|
3181 |
+
{
|
3182 |
+
"slug": "panther-reference",
|
3183 |
+
"name": "Panther Reference",
|
3184 |
+
"other_name": "Panther Group UK",
|
3185 |
+
"required_fields": [
|
3186 |
+
"tracking_account_number"
|
3187 |
+
]
|
3188 |
+
},
|
3189 |
+
{
|
3190 |
+
"slug": "paper-express",
|
3191 |
+
"name": "Paper Express",
|
3192 |
+
"other_name": "",
|
3193 |
+
"required_fields": [
|
3194 |
+
"tracking_postal_code"
|
3195 |
+
]
|
3196 |
+
},
|
3197 |
+
{
|
3198 |
+
"slug": "paperfly",
|
3199 |
+
"name": "Paperfly Private Limited",
|
3200 |
+
"other_name": "",
|
3201 |
+
"required_fields": []
|
3202 |
+
},
|
3203 |
+
{
|
3204 |
+
"slug": "paquetexpress",
|
3205 |
+
"name": "Paquetexpress",
|
3206 |
+
"other_name": "",
|
3207 |
+
"required_fields": []
|
3208 |
+
},
|
3209 |
+
{
|
3210 |
+
"slug": "parcel-force",
|
3211 |
+
"name": "Parcel Force",
|
3212 |
+
"other_name": "Parcelforce UK",
|
3213 |
+
"required_fields": []
|
3214 |
+
},
|
3215 |
+
{
|
3216 |
+
"slug": "parcel2go",
|
3217 |
+
"name": "Parcel2Go",
|
3218 |
+
"other_name": "",
|
3219 |
+
"required_fields": []
|
3220 |
+
},
|
3221 |
+
{
|
3222 |
+
"slug": "parcelled-in",
|
3223 |
+
"name": "Parcelled.in",
|
3224 |
+
"other_name": "Parcelled",
|
3225 |
+
"required_fields": []
|
3226 |
+
},
|
3227 |
+
{
|
3228 |
+
"slug": "parcelone",
|
3229 |
+
"name": "PARCEL ONE",
|
3230 |
+
"other_name": "",
|
3231 |
+
"required_fields": []
|
3232 |
+
},
|
3233 |
+
{
|
3234 |
+
"slug": "parcelpal-webhook",
|
3235 |
+
"name": "ParcelPal",
|
3236 |
+
"other_name": null,
|
3237 |
+
"required_fields": []
|
3238 |
+
},
|
3239 |
+
{
|
3240 |
+
"slug": "parcelpoint",
|
3241 |
+
"name": "ParcelPoint Pty Ltd",
|
3242 |
+
"other_name": "",
|
3243 |
+
"required_fields": [
|
3244 |
+
"tracking_key"
|
3245 |
+
]
|
3246 |
+
},
|
3247 |
+
{
|
3248 |
+
"slug": "parcelpost-sg",
|
3249 |
+
"name": "Parcel Post Singapore",
|
3250 |
+
"other_name": "ParcelPost",
|
3251 |
+
"required_fields": []
|
3252 |
+
},
|
3253 |
+
{
|
3254 |
+
"slug": "parknparcel",
|
3255 |
+
"name": "Park N Parcel",
|
3256 |
+
"other_name": "",
|
3257 |
+
"required_fields": []
|
3258 |
+
},
|
3259 |
+
{
|
3260 |
+
"slug": "pfcexpress",
|
3261 |
+
"name": "PFC Express",
|
3262 |
+
"other_name": "PFCu7687u5bb6u7269u6d41",
|
3263 |
+
"required_fields": []
|
3264 |
+
},
|
3265 |
+
{
|
3266 |
+
"slug": "pflogistics",
|
3267 |
+
"name": "PFL",
|
3268 |
+
"other_name": null,
|
3269 |
+
"required_fields": []
|
3270 |
+
},
|
3271 |
+
{
|
3272 |
+
"slug": "pickup",
|
3273 |
+
"name": "Pickupp",
|
3274 |
+
"other_name": "",
|
3275 |
+
"required_fields": []
|
3276 |
+
},
|
3277 |
+
{
|
3278 |
+
"slug": "pickupp-mys",
|
3279 |
+
"name": "PICK UPP",
|
3280 |
+
"other_name": "",
|
3281 |
+
"required_fields": []
|
3282 |
+
},
|
3283 |
+
{
|
3284 |
+
"slug": "pickupp-sgp",
|
3285 |
+
"name": "PICK UPP (Singapore)",
|
3286 |
+
"other_name": "",
|
3287 |
+
"required_fields": []
|
3288 |
+
},
|
3289 |
+
{
|
3290 |
+
"slug": "pickupp-vnm",
|
3291 |
+
"name": "Pickupp Vietnam",
|
3292 |
+
"other_name": "",
|
3293 |
+
"required_fields": []
|
3294 |
+
},
|
3295 |
+
{
|
3296 |
+
"slug": "pil-logistics",
|
3297 |
+
"name": "PIL Logistics (China) Co., Ltd",
|
3298 |
+
"other_name": "",
|
3299 |
+
"required_fields": []
|
3300 |
+
},
|
3301 |
+
{
|
3302 |
+
"slug": "pilot-freight",
|
3303 |
+
"name": "Pilot Freight Services",
|
3304 |
+
"other_name": "",
|
3305 |
+
"required_fields": []
|
3306 |
+
},
|
3307 |
+
{
|
3308 |
+
"slug": "pitney-bowes",
|
3309 |
+
"name": "Pitney Bowes",
|
3310 |
+
"other_name": "",
|
3311 |
+
"required_fields": []
|
3312 |
+
},
|
3313 |
+
{
|
3314 |
+
"slug": "pittohio",
|
3315 |
+
"name": "PITT OHIO",
|
3316 |
+
"other_name": "",
|
3317 |
+
"required_fields": []
|
3318 |
+
},
|
3319 |
+
{
|
3320 |
+
"slug": "pixsell",
|
3321 |
+
"name": "PIXSELL LOGISTICS",
|
3322 |
+
"other_name": "",
|
3323 |
+
"required_fields": []
|
3324 |
+
},
|
3325 |
+
{
|
3326 |
+
"slug": "planzer",
|
3327 |
+
"name": "Planzer Group",
|
3328 |
+
"other_name": "",
|
3329 |
+
"required_fields": [
|
3330 |
+
"tracking_postal_code"
|
3331 |
+
]
|
3332 |
+
},
|
3333 |
+
{
|
3334 |
+
"slug": "poczta-polska",
|
3335 |
+
"name": "Poczta Polska",
|
3336 |
+
"other_name": "Poland Post",
|
3337 |
+
"required_fields": []
|
3338 |
+
},
|
3339 |
+
{
|
3340 |
+
"slug": "pony-express",
|
3341 |
+
"name": "Pony express",
|
3342 |
+
"other_name": "",
|
3343 |
+
"required_fields": []
|
3344 |
+
},
|
3345 |
+
{
|
3346 |
+
"slug": "portugal-ctt",
|
3347 |
+
"name": "Portugal CTT",
|
3348 |
+
"other_name": "Correios de Portugal",
|
3349 |
+
"required_fields": []
|
3350 |
+
},
|
3351 |
+
{
|
3352 |
+
"slug": "portugal-seur",
|
3353 |
+
"name": "Portugal Seur",
|
3354 |
+
"other_name": "SEUR",
|
3355 |
+
"required_fields": []
|
3356 |
+
},
|
3357 |
+
{
|
3358 |
+
"slug": "post-serbia",
|
3359 |
+
"name": "Post Serbia",
|
3360 |
+
"other_name": "Pou0161ta Srbije",
|
3361 |
+
"required_fields": []
|
3362 |
+
},
|
3363 |
+
{
|
3364 |
+
"slug": "post-slovenia",
|
3365 |
+
"name": "Post of Slovenia",
|
3366 |
+
"other_name": "",
|
3367 |
+
"required_fields": []
|
3368 |
+
},
|
3369 |
+
{
|
3370 |
+
"slug": "post56",
|
3371 |
+
"name": "Post56",
|
3372 |
+
"other_name": "捷邮快递",
|
3373 |
+
"required_fields": []
|
3374 |
+
},
|
3375 |
+
{
|
3376 |
+
"slug": "posta-romana",
|
3377 |
+
"name": "Poșta Română",
|
3378 |
+
"other_name": "Romania Post",
|
3379 |
+
"required_fields": []
|
3380 |
+
},
|
3381 |
+
{
|
3382 |
+
"slug": "poste-italiane",
|
3383 |
+
"name": "Poste Italiane",
|
3384 |
+
"other_name": "Italian Post",
|
3385 |
+
"required_fields": []
|
3386 |
+
},
|
3387 |
+
{
|
3388 |
+
"slug": "poste-italiane-paccocelere",
|
3389 |
+
"name": "Poste Italiane Paccocelere",
|
3390 |
+
"other_name": "Italian Post EMS / Express",
|
3391 |
+
"required_fields": []
|
3392 |
+
},
|
3393 |
+
{
|
3394 |
+
"slug": "posten-norge",
|
3395 |
+
"name": "Posten Norge / Bring",
|
3396 |
+
"other_name": "Norway Post, Norska Posten",
|
3397 |
+
"required_fields": []
|
3398 |
+
},
|
3399 |
+
{
|
3400 |
+
"slug": "posti",
|
3401 |
+
"name": "Posti",
|
3402 |
+
"other_name": "Finland Post",
|
3403 |
+
"required_fields": []
|
3404 |
+
},
|
3405 |
+
{
|
3406 |
+
"slug": "postnl",
|
3407 |
+
"name": "PostNL Domestic",
|
3408 |
+
"other_name": "PostNL Pakketten, TNT Post Netherlands",
|
3409 |
+
"required_fields": [
|
3410 |
+
"tracking_postal_code"
|
3411 |
+
]
|
3412 |
+
},
|
3413 |
+
{
|
3414 |
+
"slug": "postnl-3s",
|
3415 |
+
"name": "PostNL International 3S",
|
3416 |
+
"other_name": "TNT Post parcel service United Kingdom",
|
3417 |
+
"required_fields": [
|
3418 |
+
"tracking_destination_country",
|
3419 |
+
"tracking_postal_code"
|
3420 |
+
]
|
3421 |
+
},
|
3422 |
+
{
|
3423 |
+
"slug": "postnl-international",
|
3424 |
+
"name": "PostNL International",
|
3425 |
+
"other_name": "Netherlands Post, Spring Global Mail",
|
3426 |
+
"required_fields": []
|
3427 |
+
},
|
3428 |
+
{
|
3429 |
+
"slug": "postnord",
|
3430 |
+
"name": "PostNord Logistics",
|
3431 |
+
"other_name": "Posten Norden",
|
3432 |
+
"required_fields": []
|
3433 |
+
},
|
3434 |
+
{
|
3435 |
+
"slug": "postur-is",
|
3436 |
+
"name": "Iceland Post",
|
3437 |
+
"other_name": "Postur.is, Íslandspóstur",
|
3438 |
+
"required_fields": []
|
3439 |
+
},
|
3440 |
+
{
|
3441 |
+
"slug": "ppbyb",
|
3442 |
+
"name": "PayPal Package",
|
3443 |
+
"other_name": "贝邮宝",
|
3444 |
+
"required_fields": []
|
3445 |
+
},
|
3446 |
+
{
|
3447 |
+
"slug": "primamulticipta",
|
3448 |
+
"name": "PT Prima Multi Cipta",
|
3449 |
+
"other_name": "",
|
3450 |
+
"required_fields": []
|
3451 |
+
},
|
3452 |
+
{
|
3453 |
+
"slug": "professional-couriers",
|
3454 |
+
"name": "Professional Couriers",
|
3455 |
+
"other_name": "TPC India",
|
3456 |
+
"required_fields": []
|
3457 |
+
},
|
3458 |
+
{
|
3459 |
+
"slug": "ptt-posta",
|
3460 |
+
"name": "PTT Posta",
|
3461 |
+
"other_name": "Turkish Post",
|
3462 |
+
"required_fields": []
|
3463 |
+
},
|
3464 |
+
{
|
3465 |
+
"slug": "purolator",
|
3466 |
+
"name": "Purolator",
|
3467 |
+
"other_name": "Purolator Freight",
|
3468 |
+
"required_fields": []
|
3469 |
+
},
|
3470 |
+
{
|
3471 |
+
"slug": "purolator-international",
|
3472 |
+
"name": "Purolator International",
|
3473 |
+
"other_name": "",
|
3474 |
+
"required_fields": []
|
3475 |
+
},
|
3476 |
+
{
|
3477 |
+
"slug": "qualitypost",
|
3478 |
+
"name": "QualityPost",
|
3479 |
+
"other_name": "",
|
3480 |
+
"required_fields": []
|
3481 |
+
},
|
3482 |
+
{
|
3483 |
+
"slug": "quantium",
|
3484 |
+
"name": "Quantium",
|
3485 |
+
"other_name": "u51a0u5eadu7269u6d41",
|
3486 |
+
"required_fields": []
|
3487 |
+
},
|
3488 |
+
{
|
3489 |
+
"slug": "qxpress",
|
3490 |
+
"name": "Qxpress",
|
3491 |
+
"other_name": "Qxpress Qoo10",
|
3492 |
+
"required_fields": []
|
3493 |
+
},
|
3494 |
+
{
|
3495 |
+
"slug": "raben-group",
|
3496 |
+
"name": "Raben Group",
|
3497 |
+
"other_name": "myRaben",
|
3498 |
+
"required_fields": []
|
3499 |
+
},
|
3500 |
+
{
|
3501 |
+
"slug": "raf",
|
3502 |
+
"name": "RAF Philippines",
|
3503 |
+
"other_name": "RAF Int'l. Forwarding",
|
3504 |
+
"required_fields": []
|
3505 |
+
},
|
3506 |
+
{
|
3507 |
+
"slug": "raiderex",
|
3508 |
+
"name": "RaidereX",
|
3509 |
+
"other_name": "Detrack",
|
3510 |
+
"required_fields": []
|
3511 |
+
},
|
3512 |
+
{
|
3513 |
+
"slug": "ramgroup-za",
|
3514 |
+
"name": "RAM",
|
3515 |
+
"other_name": "RAM Group",
|
3516 |
+
"required_fields": []
|
3517 |
+
},
|
3518 |
+
{
|
3519 |
+
"slug": "rcl",
|
3520 |
+
"name": "Red Carpet Logistics",
|
3521 |
+
"other_name": "",
|
3522 |
+
"required_fields": []
|
3523 |
+
},
|
3524 |
+
{
|
3525 |
+
"slug": "redjepakketje",
|
3526 |
+
"name": "Red je Pakketje",
|
3527 |
+
"other_name": null,
|
3528 |
+
"required_fields": []
|
3529 |
+
},
|
3530 |
+
{
|
3531 |
+
"slug": "redur-es",
|
3532 |
+
"name": "Redur Spain",
|
3533 |
+
"other_name": "Eurodis",
|
3534 |
+
"required_fields": []
|
3535 |
+
},
|
3536 |
+
{
|
3537 |
+
"slug": "relaiscolis",
|
3538 |
+
"name": "Relais Colis",
|
3539 |
+
"other_name": "",
|
3540 |
+
"required_fields": [
|
3541 |
+
"tracking_key"
|
3542 |
+
]
|
3543 |
+
},
|
3544 |
+
{
|
3545 |
+
"slug": "rincos",
|
3546 |
+
"name": "Rincos",
|
3547 |
+
"other_name": "",
|
3548 |
+
"required_fields": []
|
3549 |
+
},
|
3550 |
+
{
|
3551 |
+
"slug": "rl-carriers",
|
3552 |
+
"name": "RL Carriers",
|
3553 |
+
"other_name": "R+L Carriers",
|
3554 |
+
"required_fields": []
|
3555 |
+
},
|
3556 |
+
{
|
3557 |
+
"slug": "roadbull",
|
3558 |
+
"name": "Roadbull Logistics",
|
3559 |
+
"other_name": "Roadbull Logistics Pte Ltd",
|
3560 |
+
"required_fields": []
|
3561 |
+
},
|
3562 |
+
{
|
3563 |
+
"slug": "roadrunner-freight",
|
3564 |
+
"name": "Roadrunner Transport Service",
|
3565 |
+
"other_name": "",
|
3566 |
+
"required_fields": []
|
3567 |
+
},
|
3568 |
+
{
|
3569 |
+
"slug": "rocketparcel",
|
3570 |
+
"name": "Rocket Parcel International",
|
3571 |
+
"other_name": "",
|
3572 |
+
"required_fields": []
|
3573 |
+
},
|
3574 |
+
{
|
3575 |
+
"slug": "royal-mail",
|
3576 |
+
"name": "Royal Mail",
|
3577 |
+
"other_name": "Royal Mail United Kingdom",
|
3578 |
+
"required_fields": []
|
3579 |
+
},
|
3580 |
+
{
|
3581 |
+
"slug": "rpd2man",
|
3582 |
+
"name": "RPD2man Deliveries",
|
3583 |
+
"other_name": "RPD-2man",
|
3584 |
+
"required_fields": []
|
3585 |
+
},
|
3586 |
+
{
|
3587 |
+
"slug": "rpx",
|
3588 |
+
"name": "RPX Indonesia",
|
3589 |
+
"other_name": "Repex Perdana International",
|
3590 |
+
"required_fields": []
|
3591 |
+
},
|
3592 |
+
{
|
3593 |
+
"slug": "rpxonline",
|
3594 |
+
"name": "RPX Online",
|
3595 |
+
"other_name": "Cathay Pacific",
|
3596 |
+
"required_fields": []
|
3597 |
+
},
|
3598 |
+
{
|
3599 |
+
"slug": "rrdonnelley",
|
3600 |
+
"name": "RRD International Logistics U.S.A",
|
3601 |
+
"other_name": "RRD",
|
3602 |
+
"required_fields": []
|
3603 |
+
},
|
3604 |
+
{
|
3605 |
+
"slug": "russian-post",
|
3606 |
+
"name": "Russian Post",
|
3607 |
+
"other_name": "Почта России, EMS Post RU",
|
3608 |
+
"required_fields": []
|
3609 |
+
},
|
3610 |
+
{
|
3611 |
+
"slug": "ruston",
|
3612 |
+
"name": "Ruston",
|
3613 |
+
"other_name": "",
|
3614 |
+
"required_fields": []
|
3615 |
+
},
|
3616 |
+
{
|
3617 |
+
"slug": "rzyexpress",
|
3618 |
+
"name": "RZY Express",
|
3619 |
+
"other_name": "RZYExpress",
|
3620 |
+
"required_fields": []
|
3621 |
+
},
|
3622 |
+
{
|
3623 |
+
"slug": "safexpress",
|
3624 |
+
"name": "Safexpress",
|
3625 |
+
"other_name": "Safexpress",
|
3626 |
+
"required_fields": []
|
3627 |
+
},
|
3628 |
+
{
|
3629 |
+
"slug": "sagawa",
|
3630 |
+
"name": "Sagawa",
|
3631 |
+
"other_name": "佐川急便",
|
3632 |
+
"required_fields": []
|
3633 |
+
},
|
3634 |
+
{
|
3635 |
+
"slug": "saia-freight",
|
3636 |
+
"name": "Saia LTL Freight",
|
3637 |
+
"other_name": "",
|
3638 |
+
"required_fields": []
|
3639 |
+
},
|
3640 |
+
{
|
3641 |
+
"slug": "sailpost",
|
3642 |
+
"name": "SAILPOST",
|
3643 |
+
"other_name": "",
|
3644 |
+
"required_fields": []
|
3645 |
+
},
|
3646 |
+
{
|
3647 |
+
"slug": "sap-express",
|
3648 |
+
"name": "SAP EXPRESS",
|
3649 |
+
"other_name": "",
|
3650 |
+
"required_fields": []
|
3651 |
+
},
|
3652 |
+
{
|
3653 |
+
"slug": "sapo",
|
3654 |
+
"name": "South African Post Office",
|
3655 |
+
"other_name": "South African Post Office",
|
3656 |
+
"required_fields": []
|
3657 |
+
},
|
3658 |
+
{
|
3659 |
+
"slug": "saudi-post",
|
3660 |
+
"name": "Saudi Post",
|
3661 |
+
"other_name": "البريد السعودي",
|
3662 |
+
"required_fields": []
|
3663 |
+
},
|
3664 |
+
{
|
3665 |
+
"slug": "scudex-express",
|
3666 |
+
"name": "Scudex Express",
|
3667 |
+
"other_name": "",
|
3668 |
+
"required_fields": []
|
3669 |
+
},
|
3670 |
+
{
|
3671 |
+
"slug": "sefl",
|
3672 |
+
"name": "Southeastern Freight Lines",
|
3673 |
+
"other_name": "",
|
3674 |
+
"required_fields": []
|
3675 |
+
},
|
3676 |
+
{
|
3677 |
+
"slug": "seino",
|
3678 |
+
"name": "Seino",
|
3679 |
+
"other_name": "",
|
3680 |
+
"required_fields": []
|
3681 |
+
},
|
3682 |
+
{
|
3683 |
+
"slug": "seko-sftp",
|
3684 |
+
"name": "SEKO Worldwide, LLC",
|
3685 |
+
"other_name": "SEKO Logistics",
|
3686 |
+
"required_fields": []
|
3687 |
+
},
|
3688 |
+
{
|
3689 |
+
"slug": "sekologistics",
|
3690 |
+
"name": "SEKO Logistics",
|
3691 |
+
"other_name": "SEKO",
|
3692 |
+
"required_fields": []
|
3693 |
+
},
|
3694 |
+
{
|
3695 |
+
"slug": "sending",
|
3696 |
+
"name": "Sending Transporte Urgente y Comunicacion, S.A.U",
|
3697 |
+
"other_name": "",
|
3698 |
+
"required_fields": []
|
3699 |
+
},
|
3700 |
+
{
|
3701 |
+
"slug": "sendit",
|
3702 |
+
"name": "Sendit",
|
3703 |
+
"other_name": "",
|
3704 |
+
"required_fields": []
|
3705 |
+
},
|
3706 |
+
{
|
3707 |
+
"slug": "sendle",
|
3708 |
+
"name": "Sendle",
|
3709 |
+
"other_name": "",
|
3710 |
+
"required_fields": []
|
3711 |
+
},
|
3712 |
+
{
|
3713 |
+
"slug": "sf-express",
|
3714 |
+
"name": "SF Express",
|
3715 |
+
"other_name": "順豊快遞, SF",
|
3716 |
+
"required_fields": []
|
3717 |
+
},
|
3718 |
+
{
|
3719 |
+
"slug": "sf-express-webhook",
|
3720 |
+
"name": "SF Express (Webhook)",
|
3721 |
+
"other_name": "顺丰速运 (丰桥路由状态推送)",
|
3722 |
+
"required_fields": []
|
3723 |
+
},
|
3724 |
+
{
|
3725 |
+
"slug": "sfb2c",
|
3726 |
+
"name": "S.F International",
|
3727 |
+
"other_name": "順豐國際",
|
3728 |
+
"required_fields": []
|
3729 |
+
},
|
3730 |
+
{
|
3731 |
+
"slug": "sfc",
|
3732 |
+
"name": "SFC",
|
3733 |
+
"other_name": "三态速递",
|
3734 |
+
"required_fields": []
|
3735 |
+
},
|
3736 |
+
{
|
3737 |
+
"slug": "sfcservice",
|
3738 |
+
"name": "SFC Service",
|
3739 |
+
"other_name": "u6df1u5733u4e09u6001u56fdu9645u901fu9012",
|
3740 |
+
"required_fields": []
|
3741 |
+
},
|
3742 |
+
{
|
3743 |
+
"slug": "sfplus-webhook",
|
3744 |
+
"name": "SF Plus",
|
3745 |
+
"other_name": "Kin Shun Information Technology Limited",
|
3746 |
+
"required_fields": []
|
3747 |
+
},
|
3748 |
+
{
|
3749 |
+
"slug": "ship-it-asia",
|
3750 |
+
"name": "Ship It Asia",
|
3751 |
+
"other_name": "",
|
3752 |
+
"required_fields": []
|
3753 |
+
},
|
3754 |
+
{
|
3755 |
+
"slug": "shippify",
|
3756 |
+
"name": "Shippify, Inc",
|
3757 |
+
"other_name": "",
|
3758 |
+
"required_fields": []
|
3759 |
+
},
|
3760 |
+
{
|
3761 |
+
"slug": "shippit",
|
3762 |
+
"name": "Shippit",
|
3763 |
+
"other_name": "",
|
3764 |
+
"required_fields": []
|
3765 |
+
},
|
3766 |
+
{
|
3767 |
+
"slug": "shiptor",
|
3768 |
+
"name": "Shiptor",
|
3769 |
+
"other_name": "",
|
3770 |
+
"required_fields": []
|
3771 |
+
},
|
3772 |
+
{
|
3773 |
+
"slug": "shopfans",
|
3774 |
+
"name": "ShopfansRU LLC",
|
3775 |
+
"other_name": "",
|
3776 |
+
"required_fields": []
|
3777 |
+
},
|
3778 |
+
{
|
3779 |
+
"slug": "shree-maruti",
|
3780 |
+
"name": "Shree Maruti Courier Services Pvt Ltd",
|
3781 |
+
"other_name": "",
|
3782 |
+
"required_fields": []
|
3783 |
+
},
|
3784 |
+
{
|
3785 |
+
"slug": "shreetirupati",
|
3786 |
+
"name": "SHREE TIRUPATI COURIER SERVICES PVT. LTD.",
|
3787 |
+
"other_name": "",
|
3788 |
+
"required_fields": []
|
3789 |
+
},
|
3790 |
+
{
|
3791 |
+
"slug": "sic-teliway",
|
3792 |
+
"name": "Teliway SIC Express",
|
3793 |
+
"other_name": "Prevote",
|
3794 |
+
"required_fields": []
|
3795 |
+
},
|
3796 |
+
{
|
3797 |
+
"slug": "simplypost",
|
3798 |
+
"name": "J & T Express Singapore",
|
3799 |
+
"other_name": "",
|
3800 |
+
"required_fields": []
|
3801 |
+
},
|
3802 |
+
{
|
3803 |
+
"slug": "singapore-post",
|
3804 |
+
"name": "Singapore Post",
|
3805 |
+
"other_name": "SingPost",
|
3806 |
+
"required_fields": []
|
3807 |
+
},
|
3808 |
+
{
|
3809 |
+
"slug": "singapore-speedpost",
|
3810 |
+
"name": "Singapore Speedpost",
|
3811 |
+
"other_name": "Singapore EMS",
|
3812 |
+
"required_fields": []
|
3813 |
+
},
|
3814 |
+
{
|
3815 |
+
"slug": "siodemka",
|
3816 |
+
"name": "Siodemka",
|
3817 |
+
"other_name": "Siodemka Kurier",
|
3818 |
+
"required_fields": []
|
3819 |
+
},
|
3820 |
+
{
|
3821 |
+
"slug": "sk-posta",
|
3822 |
+
"name": "Slovenská pošta, a.s.",
|
3823 |
+
"other_name": "",
|
3824 |
+
"required_fields": []
|
3825 |
+
},
|
3826 |
+
{
|
3827 |
+
"slug": "sky-postal",
|
3828 |
+
"name": "SkyPostal",
|
3829 |
+
"other_name": "",
|
3830 |
+
"required_fields": []
|
3831 |
+
},
|
3832 |
+
{
|
3833 |
+
"slug": "skybox",
|
3834 |
+
"name": "SKYBOX",
|
3835 |
+
"other_name": "",
|
3836 |
+
"required_fields": []
|
3837 |
+
},
|
3838 |
+
{
|
3839 |
+
"slug": "skynet",
|
3840 |
+
"name": "SkyNet Malaysia",
|
3841 |
+
"other_name": "SkyNet MY",
|
3842 |
+
"required_fields": []
|
3843 |
+
},
|
3844 |
+
{
|
3845 |
+
"slug": "skynet-za",
|
3846 |
+
"name": "Skynet World Wide Express South Africa",
|
3847 |
+
"other_name": "",
|
3848 |
+
"required_fields": []
|
3849 |
+
},
|
3850 |
+
{
|
3851 |
+
"slug": "skynetworldwide",
|
3852 |
+
"name": "SkyNet Worldwide Express",
|
3853 |
+
"other_name": "Skynetwwe",
|
3854 |
+
"required_fields": []
|
3855 |
+
},
|
3856 |
+
{
|
3857 |
+
"slug": "skynetworldwide-uae",
|
3858 |
+
"name": "SkyNet Worldwide Express UAE",
|
3859 |
+
"other_name": "",
|
3860 |
+
"required_fields": []
|
3861 |
+
},
|
3862 |
+
{
|
3863 |
+
"slug": "skynetworldwide-uk",
|
3864 |
+
"name": "Skynet Worldwide Express UK",
|
3865 |
+
"other_name": "Skynet UK",
|
3866 |
+
"required_fields": []
|
3867 |
+
},
|
3868 |
+
{
|
3869 |
+
"slug": "skypostal",
|
3870 |
+
"name": "Asendia HK – Premium Service (LATAM)",
|
3871 |
+
"other_name": "SkyPostal (Postrac)",
|
3872 |
+
"required_fields": []
|
3873 |
+
},
|
3874 |
+
{
|
3875 |
+
"slug": "smg-express",
|
3876 |
+
"name": "SMG Direct",
|
3877 |
+
"other_name": "",
|
3878 |
+
"required_fields": []
|
3879 |
+
},
|
3880 |
+
{
|
3881 |
+
"slug": "smooth",
|
3882 |
+
"name": "Smooth Couriers",
|
3883 |
+
"other_name": "",
|
3884 |
+
"required_fields": []
|
3885 |
+
},
|
3886 |
+
{
|
3887 |
+
"slug": "smsa-express",
|
3888 |
+
"name": "SMSA Express",
|
3889 |
+
"other_name": "",
|
3890 |
+
"required_fields": []
|
3891 |
+
},
|
3892 |
+
{
|
3893 |
+
"slug": "sonictl",
|
3894 |
+
"name": "Sonic Transportation & Logistics",
|
3895 |
+
"other_name": "",
|
3896 |
+
"required_fields": []
|
3897 |
+
},
|
3898 |
+
{
|
3899 |
+
"slug": "spain-correos-es",
|
3900 |
+
"name": "Correos de España",
|
3901 |
+
"other_name": "Spain Post, ChronoExpress",
|
3902 |
+
"required_fields": []
|
3903 |
+
},
|
3904 |
+
{
|
3905 |
+
"slug": "spanish-seur",
|
3906 |
+
"name": "Spanish Seur",
|
3907 |
+
"other_name": "SEUR",
|
3908 |
+
"required_fields": []
|
3909 |
+
},
|
3910 |
+
{
|
3911 |
+
"slug": "spanish-seur-api",
|
3912 |
+
"name": "Spanish Seur API",
|
3913 |
+
"other_name": "",
|
3914 |
+
"required_fields": []
|
3915 |
+
},
|
3916 |
+
{
|
3917 |
+
"slug": "specialisedfreight-za",
|
3918 |
+
"name": "Specialised Freight",
|
3919 |
+
"other_name": "SFS",
|
3920 |
+
"required_fields": []
|
3921 |
+
},
|
3922 |
+
{
|
3923 |
+
"slug": "spectran",
|
3924 |
+
"name": "Spectran",
|
3925 |
+
"other_name": null,
|
3926 |
+
"required_fields": []
|
3927 |
+
},
|
3928 |
+
{
|
3929 |
+
"slug": "speedcouriers-gr",
|
3930 |
+
"name": "Speed Couriers",
|
3931 |
+
"other_name": "Speed Couriers",
|
3932 |
+
"required_fields": []
|
3933 |
+
},
|
3934 |
+
{
|
3935 |
+
"slug": "speedee",
|
3936 |
+
"name": "Spee-Dee Delivery",
|
3937 |
+
"other_name": "",
|
3938 |
+
"required_fields": []
|
3939 |
+
},
|
3940 |
+
{
|
3941 |
+
"slug": "speedexcourier",
|
3942 |
+
"name": "Speedex Courier",
|
3943 |
+
"other_name": "Speedex Courier",
|
3944 |
+
"required_fields": []
|
3945 |
+
},
|
3946 |
+
{
|
3947 |
+
"slug": "speedy",
|
3948 |
+
"name": "Speedy",
|
3949 |
+
"other_name": "",
|
3950 |
+
"required_fields": []
|
3951 |
+
},
|
3952 |
+
{
|
3953 |
+
"slug": "spoton",
|
3954 |
+
"name": "SPOTON Logistics Pvt Ltd",
|
3955 |
+
"other_name": "",
|
3956 |
+
"required_fields": []
|
3957 |
+
},
|
3958 |
+
{
|
3959 |
+
"slug": "spring-gds",
|
3960 |
+
"name": "Spring GDS",
|
3961 |
+
"other_name": "",
|
3962 |
+
"required_fields": []
|
3963 |
+
},
|
3964 |
+
{
|
3965 |
+
"slug": "sprint-pack",
|
3966 |
+
"name": "SPRINT PACK",
|
3967 |
+
"other_name": "",
|
3968 |
+
"required_fields": []
|
3969 |
+
},
|
3970 |
+
{
|
3971 |
+
"slug": "srekorea",
|
3972 |
+
"name": "SRE Korea",
|
3973 |
+
"other_name": "SRE 배송서비스",
|
3974 |
+
"required_fields": []
|
3975 |
+
},
|
3976 |
+
{
|
3977 |
+
"slug": "stallionexpress",
|
3978 |
+
"name": "Stallion Express",
|
3979 |
+
"other_name": "",
|
3980 |
+
"required_fields": []
|
3981 |
+
},
|
3982 |
+
{
|
3983 |
+
"slug": "star-track",
|
3984 |
+
"name": "StarTrack",
|
3985 |
+
"other_name": "Star Track",
|
3986 |
+
"required_fields": []
|
3987 |
+
},
|
3988 |
+
{
|
3989 |
+
"slug": "star-track-courier",
|
3990 |
+
"name": "Star Track Courier",
|
3991 |
+
"other_name": "",
|
3992 |
+
"required_fields": [
|
3993 |
+
"tracking_state"
|
3994 |
+
]
|
3995 |
+
},
|
3996 |
+
{
|
3997 |
+
"slug": "star-track-express",
|
3998 |
+
"name": "Star Track Express",
|
3999 |
+
"other_name": "AaE Australian air Express",
|
4000 |
+
"required_fields": []
|
4001 |
+
},
|
4002 |
+
{
|
4003 |
+
"slug": "starken",
|
4004 |
+
"name": "STARKEN",
|
4005 |
+
"other_name": "",
|
4006 |
+
"required_fields": []
|
4007 |
+
},
|
4008 |
+
{
|
4009 |
+
"slug": "sto",
|
4010 |
+
"name": "STO Express",
|
4011 |
+
"other_name": "申通快递, Shentong Express",
|
4012 |
+
"required_fields": []
|
4013 |
+
},
|
4014 |
+
{
|
4015 |
+
"slug": "stone3pl",
|
4016 |
+
"name": "STONE3PL",
|
4017 |
+
"other_name": null,
|
4018 |
+
"required_fields": []
|
4019 |
+
},
|
4020 |
+
{
|
4021 |
+
"slug": "sutton",
|
4022 |
+
"name": "Sutton Transport",
|
4023 |
+
"other_name": "",
|
4024 |
+
"required_fields": []
|
4025 |
+
},
|
4026 |
+
{
|
4027 |
+
"slug": "sweden-posten",
|
4028 |
+
"name": "PostNord Sweden",
|
4029 |
+
"other_name": "Sweden Post, Posten, Sweden Posten",
|
4030 |
+
"required_fields": []
|
4031 |
+
},
|
4032 |
+
{
|
4033 |
+
"slug": "swiss-post",
|
4034 |
+
"name": "Swiss Post",
|
4035 |
+
"other_name": "La Poste Suisse, Die Schweizerische Post, Die Post",
|
4036 |
+
"required_fields": []
|
4037 |
+
},
|
4038 |
+
{
|
4039 |
+
"slug": "sypost",
|
4040 |
+
"name": "Sunyou Post",
|
4041 |
+
"other_name": "",
|
4042 |
+
"required_fields": []
|
4043 |
+
},
|
4044 |
+
{
|
4045 |
+
"slug": "szdpex",
|
4046 |
+
"name": "DPEX China",
|
4047 |
+
"other_name": "DPEX(深圳)国际物流, Toll China",
|
4048 |
+
"required_fields": []
|
4049 |
+
},
|
4050 |
+
{
|
4051 |
+
"slug": "szendex",
|
4052 |
+
"name": "SZENDEX",
|
4053 |
+
"other_name": null,
|
4054 |
+
"required_fields": []
|
4055 |
+
},
|
4056 |
+
{
|
4057 |
+
"slug": "taiwan-post",
|
4058 |
+
"name": "Taiwan Post",
|
4059 |
+
"other_name": "Chunghwa Post, 台灣中華郵政",
|
4060 |
+
"required_fields": []
|
4061 |
+
},
|
4062 |
+
{
|
4063 |
+
"slug": "taqbin-hk",
|
4064 |
+
"name": "TAQBIN Hong Kong",
|
4065 |
+
"other_name": "Yamat, 雅瑪多運輸- 宅急便",
|
4066 |
+
"required_fields": []
|
4067 |
+
},
|
4068 |
+
{
|
4069 |
+
"slug": "taqbin-jp",
|
4070 |
+
"name": "Yamato Japan",
|
4071 |
+
"other_name": "ヤマト運輸, TAQBIN",
|
4072 |
+
"required_fields": []
|
4073 |
+
},
|
4074 |
+
{
|
4075 |
+
"slug": "taqbin-my",
|
4076 |
+
"name": "TAQBIN Malaysia",
|
4077 |
+
"other_name": "TAQBIN Malaysia",
|
4078 |
+
"required_fields": []
|
4079 |
+
},
|
4080 |
+
{
|
4081 |
+
"slug": "taqbin-sg",
|
4082 |
+
"name": "TAQBIN Singapore",
|
4083 |
+
"other_name": "Yamato Singapore",
|
4084 |
+
"required_fields": []
|
4085 |
+
},
|
4086 |
+
{
|
4087 |
+
"slug": "taqbin-taiwan",
|
4088 |
+
"name": "PRESIDENT TRANSNET CORP",
|
4089 |
+
"other_name": "",
|
4090 |
+
"required_fields": []
|
4091 |
+
},
|
4092 |
+
{
|
4093 |
+
"slug": "tarrive",
|
4094 |
+
"name": "TONDA GLOBAL",
|
4095 |
+
"other_name": "",
|
4096 |
+
"required_fields": []
|
4097 |
+
},
|
4098 |
+
{
|
4099 |
+
"slug": "taxydromiki",
|
4100 |
+
"name": "Geniki Taxydromiki",
|
4101 |
+
"other_name": "ΓΕΝΙΚΗ ΤΑΧΥΔΡΟΜΙΚΗ",
|
4102 |
+
"required_fields": []
|
4103 |
+
},
|
4104 |
+
{
|
4105 |
+
"slug": "tazmanian-freight",
|
4106 |
+
"name": "Tazmanian Freight Systems",
|
4107 |
+
"other_name": "",
|
4108 |
+
"required_fields": []
|
4109 |
+
},
|
4110 |
+
{
|
4111 |
+
"slug": "tck-express",
|
4112 |
+
"name": "TCK Express",
|
4113 |
+
"other_name": "",
|
4114 |
+
"required_fields": []
|
4115 |
+
},
|
4116 |
+
{
|
4117 |
+
"slug": "tcs",
|
4118 |
+
"name": "TCS",
|
4119 |
+
"other_name": "",
|
4120 |
+
"required_fields": []
|
4121 |
+
},
|
4122 |
+
{
|
4123 |
+
"slug": "tfm",
|
4124 |
+
"name": "TFM Xpress",
|
4125 |
+
"other_name": "",
|
4126 |
+
"required_fields": [
|
4127 |
+
"tracking_postal_code"
|
4128 |
+
]
|
4129 |
+
},
|
4130 |
+
{
|
4131 |
+
"slug": "tforce-finalmile",
|
4132 |
+
"name": "TForce Final Mile",
|
4133 |
+
"other_name": "",
|
4134 |
+
"required_fields": []
|
4135 |
+
},
|
4136 |
+
{
|
4137 |
+
"slug": "tgx",
|
4138 |
+
"name": "Kerry Express Hong Kong",
|
4139 |
+
"other_name": "Top Gun Express, 精英速運, TGX",
|
4140 |
+
"required_fields": []
|
4141 |
+
},
|
4142 |
+
{
|
4143 |
+
"slug": "thailand-post",
|
4144 |
+
"name": "Thailand Thai Post",
|
4145 |
+
"other_name": "ไปรษณีย์ไทย",
|
4146 |
+
"required_fields": []
|
4147 |
+
},
|
4148 |
+
{
|
4149 |
+
"slug": "thecourierguy",
|
4150 |
+
"name": "The Courier Guy",
|
4151 |
+
"other_name": "TheCourierGuy",
|
4152 |
+
"required_fields": []
|
4153 |
+
},
|
4154 |
+
{
|
4155 |
+
"slug": "thedeliverygroup",
|
4156 |
+
"name": "TDG – The Delivery Group",
|
4157 |
+
"other_name": "",
|
4158 |
+
"required_fields": [
|
4159 |
+
"tracking_postal_code"
|
4160 |
+
]
|
4161 |
+
},
|
4162 |
+
{
|
4163 |
+
"slug": "thenile-webhook",
|
4164 |
+
"name": "SortHub",
|
4165 |
+
"other_name": "",
|
4166 |
+
"required_fields": []
|
4167 |
+
},
|
4168 |
+
{
|
4169 |
+
"slug": "tiki",
|
4170 |
+
"name": "Tiki",
|
4171 |
+
"other_name": "Citra Van Titipan Kilat",
|
4172 |
+
"required_fields": []
|
4173 |
+
},
|
4174 |
+
{
|
4175 |
+
"slug": "tipsa",
|
4176 |
+
"name": "TIPSA",
|
4177 |
+
"other_name": "",
|
4178 |
+
"required_fields": []
|
4179 |
+
},
|
4180 |
+
{
|
4181 |
+
"slug": "tnt",
|
4182 |
+
"name": "TNT",
|
4183 |
+
"other_name": "TNT Express",
|
4184 |
+
"required_fields": []
|
4185 |
+
},
|
4186 |
+
{
|
4187 |
+
"slug": "tnt-au",
|
4188 |
+
"name": "TNT Australia",
|
4189 |
+
"other_name": "TNT AU",
|
4190 |
+
"required_fields": []
|
4191 |
+
},
|
4192 |
+
{
|
4193 |
+
"slug": "tnt-click",
|
4194 |
+
"name": "TNT-Click Italy",
|
4195 |
+
"other_name": "TNT Italy",
|
4196 |
+
"required_fields": []
|
4197 |
+
},
|
4198 |
+
{
|
4199 |
+
"slug": "tnt-fr",
|
4200 |
+
"name": "TNT France",
|
4201 |
+
"other_name": "TNT Express FR",
|
4202 |
+
"required_fields": []
|
4203 |
+
},
|
4204 |
+
{
|
4205 |
+
"slug": "tnt-it",
|
4206 |
+
"name": "TNT Italy",
|
4207 |
+
"other_name": "TNT Express IT",
|
4208 |
+
"required_fields": []
|
4209 |
+
},
|
4210 |
+
{
|
4211 |
+
"slug": "tnt-reference",
|
4212 |
+
"name": "TNT Reference",
|
4213 |
+
"other_name": "TNT consignment reference",
|
4214 |
+
"required_fields": []
|
4215 |
+
},
|
4216 |
+
{
|
4217 |
+
"slug": "tnt-uk",
|
4218 |
+
"name": "TNT UK",
|
4219 |
+
"other_name": "TNT United Kingdom",
|
4220 |
+
"required_fields": []
|
4221 |
+
},
|
4222 |
+
{
|
4223 |
+
"slug": "tnt-uk-reference",
|
4224 |
+
"name": "TNT UK Reference",
|
4225 |
+
"other_name": "TNT UK consignment reference",
|
4226 |
+
"required_fields": []
|
4227 |
+
},
|
4228 |
+
{
|
4229 |
+
"slug": "tntpost-it",
|
4230 |
+
"name": "Nexive (TNT Post Italy)",
|
4231 |
+
"other_name": "Postnl TNT",
|
4232 |
+
"required_fields": []
|
4233 |
+
},
|
4234 |
+
{
|
4235 |
+
"slug": "toll-ipec",
|
4236 |
+
"name": "Toll IPEC",
|
4237 |
+
"other_name": "Toll Express",
|
4238 |
+
"required_fields": []
|
4239 |
+
},
|
4240 |
+
{
|
4241 |
+
"slug": "toll-nz",
|
4242 |
+
"name": "Toll New Zealand",
|
4243 |
+
"other_name": "",
|
4244 |
+
"required_fields": []
|
4245 |
+
},
|
4246 |
+
{
|
4247 |
+
"slug": "toll-priority",
|
4248 |
+
"name": "Toll Priority",
|
4249 |
+
"other_name": "Toll Group, Toll Priority",
|
4250 |
+
"required_fields": []
|
4251 |
+
},
|
4252 |
+
{
|
4253 |
+
"slug": "tolos",
|
4254 |
+
"name": "Tolos",
|
4255 |
+
"other_name": "",
|
4256 |
+
"required_fields": []
|
4257 |
+
},
|
4258 |
+
{
|
4259 |
+
"slug": "tophatterexpress",
|
4260 |
+
"name": "Tophatter Express",
|
4261 |
+
"other_name": "",
|
4262 |
+
"required_fields": []
|
4263 |
+
},
|
4264 |
+
{
|
4265 |
+
"slug": "topyou",
|
4266 |
+
"name": "TopYou",
|
4267 |
+
"other_name": null,
|
4268 |
+
"required_fields": []
|
4269 |
+
},
|
4270 |
+
{
|
4271 |
+
"slug": "total-express",
|
4272 |
+
"name": "Total Express",
|
4273 |
+
"other_name": "",
|
4274 |
+
"required_fields": [
|
4275 |
+
"tracking_account_number",
|
4276 |
+
"tracking_key"
|
4277 |
+
]
|
4278 |
+
},
|
4279 |
+
{
|
4280 |
+
"slug": "tourline",
|
4281 |
+
"name": "tourline",
|
4282 |
+
"other_name": "ctt",
|
4283 |
+
"required_fields": []
|
4284 |
+
},
|
4285 |
+
{
|
4286 |
+
"slug": "tourline-reference",
|
4287 |
+
"name": "Tourline Express",
|
4288 |
+
"other_name": "",
|
4289 |
+
"required_fields": []
|
4290 |
+
},
|
4291 |
+
{
|
4292 |
+
"slug": "trakpak",
|
4293 |
+
"name": "TrakPak",
|
4294 |
+
"other_name": "bpost international P2P Mailing Trak Pak",
|
4295 |
+
"required_fields": []
|
4296 |
+
},
|
4297 |
+
{
|
4298 |
+
"slug": "trans-kargo",
|
4299 |
+
"name": "Trans Kargo Internasional",
|
4300 |
+
"other_name": "",
|
4301 |
+
"required_fields": []
|
4302 |
+
},
|
4303 |
+
{
|
4304 |
+
"slug": "transmission-nl",
|
4305 |
+
"name": "TransMission",
|
4306 |
+
"other_name": "mijnzending",
|
4307 |
+
"required_fields": [
|
4308 |
+
"tracking_postal_code"
|
4309 |
+
]
|
4310 |
+
},
|
4311 |
+
{
|
4312 |
+
"slug": "trunkrs-webhook",
|
4313 |
+
"name": "Trunkrs",
|
4314 |
+
"other_name": "",
|
4315 |
+
"required_fields": []
|
4316 |
+
},
|
4317 |
+
{
|
4318 |
+
"slug": "tuffnells",
|
4319 |
+
"name": "Tuffnells Parcels Express",
|
4320 |
+
"other_name": "",
|
4321 |
+
"required_fields": [
|
4322 |
+
"tracking_account_number",
|
4323 |
+
"tracking_postal_code"
|
4324 |
+
]
|
4325 |
+
},
|
4326 |
+
{
|
4327 |
+
"slug": "tuffnells-reference",
|
4328 |
+
"name": "Tuffnells Parcels Express- Reference",
|
4329 |
+
"other_name": "",
|
4330 |
+
"required_fields": [
|
4331 |
+
"tracking_postal_code"
|
4332 |
+
]
|
4333 |
+
},
|
4334 |
+
{
|
4335 |
+
"slug": "ubi-logistics",
|
4336 |
+
"name": "UBI Smart Parcel",
|
4337 |
+
"other_name": "",
|
4338 |
+
"required_fields": []
|
4339 |
+
},
|
4340 |
+
{
|
4341 |
+
"slug": "uds",
|
4342 |
+
"name": "United Delivery Service, Ltd",
|
4343 |
+
"other_name": "",
|
4344 |
+
"required_fields": []
|
4345 |
+
},
|
4346 |
+
{
|
4347 |
+
"slug": "uk-mail",
|
4348 |
+
"name": "UK Mail",
|
4349 |
+
"other_name": "Business Post Group",
|
4350 |
+
"required_fields": []
|
4351 |
+
},
|
4352 |
+
{
|
4353 |
+
"slug": "ukrposhta",
|
4354 |
+
"name": "UkrPoshta",
|
4355 |
+
"other_name": "Укрпошта",
|
4356 |
+
"required_fields": []
|
4357 |
+
},
|
4358 |
+
{
|
4359 |
+
"slug": "up-express",
|
4360 |
+
"name": "UP-express",
|
4361 |
+
"other_name": "",
|
4362 |
+
"required_fields": []
|
4363 |
+
},
|
4364 |
+
{
|
4365 |
+
"slug": "ups",
|
4366 |
+
"name": "UPS",
|
4367 |
+
"other_name": "United Parcel Service",
|
4368 |
+
"required_fields": []
|
4369 |
+
},
|
4370 |
+
{
|
4371 |
+
"slug": "ups-freight",
|
4372 |
+
"name": "UPS Freight",
|
4373 |
+
"other_name": "UPS LTL and Truckload",
|
4374 |
+
"required_fields": []
|
4375 |
+
},
|
4376 |
+
{
|
4377 |
+
"slug": "ups-mi",
|
4378 |
+
"name": "UPS Mail Innovations",
|
4379 |
+
"other_name": "UPS MI",
|
4380 |
+
"required_fields": []
|
4381 |
+
},
|
4382 |
+
{
|
4383 |
+
"slug": "urgent-cargus",
|
4384 |
+
"name": "Urgent Cargus",
|
4385 |
+
"other_name": "",
|
4386 |
+
"required_fields": []
|
4387 |
+
},
|
4388 |
+
{
|
4389 |
+
"slug": "usf-reddaway",
|
4390 |
+
"name": "USF Reddaway",
|
4391 |
+
"other_name": "",
|
4392 |
+
"required_fields": []
|
4393 |
+
},
|
4394 |
+
{
|
4395 |
+
"slug": "uship",
|
4396 |
+
"name": "uShip",
|
4397 |
+
"other_name": "",
|
4398 |
+
"required_fields": []
|
4399 |
+
},
|
4400 |
+
{
|
4401 |
+
"slug": "usps",
|
4402 |
+
"name": "USPS",
|
4403 |
+
"other_name": "United States Postal Service",
|
4404 |
+
"required_fields": []
|
4405 |
+
},
|
4406 |
+
{
|
4407 |
+
"slug": "usps-webhook",
|
4408 |
+
"name": "USPS Informed Visibility - Webhook",
|
4409 |
+
"other_name": "USPS IV",
|
4410 |
+
"required_fields": []
|
4411 |
+
},
|
4412 |
+
{
|
4413 |
+
"slug": "via-express",
|
4414 |
+
"name": "Viaxpress",
|
4415 |
+
"other_name": "",
|
4416 |
+
"required_fields": []
|
4417 |
+
},
|
4418 |
+
{
|
4419 |
+
"slug": "viettelpost",
|
4420 |
+
"name": "ViettelPost",
|
4421 |
+
"other_name": "Bưu chính Viettel",
|
4422 |
+
"required_fields": []
|
4423 |
+
},
|
4424 |
+
{
|
4425 |
+
"slug": "virtransport",
|
4426 |
+
"name": "VIR Transport",
|
4427 |
+
"other_name": "",
|
4428 |
+
"required_fields": [
|
4429 |
+
"tracking_account_number"
|
4430 |
+
]
|
4431 |
+
},
|
4432 |
+
{
|
4433 |
+
"slug": "viwo",
|
4434 |
+
"name": "VIWO IoT",
|
4435 |
+
"other_name": "",
|
4436 |
+
"required_fields": []
|
4437 |
+
},
|
4438 |
+
{
|
4439 |
+
"slug": "vnpost",
|
4440 |
+
"name": "Vietnam Post",
|
4441 |
+
"other_name": "VNPost",
|
4442 |
+
"required_fields": []
|
4443 |
+
},
|
4444 |
+
{
|
4445 |
+
"slug": "vnpost-ems",
|
4446 |
+
"name": "Vietnam Post EMS",
|
4447 |
+
"other_name": "VNPost EMS",
|
4448 |
+
"required_fields": []
|
4449 |
+
},
|
4450 |
+
{
|
4451 |
+
"slug": "wahana",
|
4452 |
+
"name": "Wahana",
|
4453 |
+
"other_name": "Wahana Indonesia",
|
4454 |
+
"required_fields": []
|
4455 |
+
},
|
4456 |
+
{
|
4457 |
+
"slug": "wanbexpress",
|
4458 |
+
"name": "WanbExpress",
|
4459 |
+
"other_name": "",
|
4460 |
+
"required_fields": []
|
4461 |
+
},
|
4462 |
+
{
|
4463 |
+
"slug": "watkins-shepard",
|
4464 |
+
"name": "Watkins Shepard",
|
4465 |
+
"other_name": "",
|
4466 |
+
"required_fields": []
|
4467 |
+
},
|
4468 |
+
{
|
4469 |
+
"slug": "weaship",
|
4470 |
+
"name": "Weaship",
|
4471 |
+
"other_name": "",
|
4472 |
+
"required_fields": []
|
4473 |
+
},
|
4474 |
+
{
|
4475 |
+
"slug": "wedo",
|
4476 |
+
"name": "WeDo Logistics",
|
4477 |
+
"other_name": "運德物流",
|
4478 |
+
"required_fields": []
|
4479 |
+
},
|
4480 |
+
{
|
4481 |
+
"slug": "wepost",
|
4482 |
+
"name": "WePost Logistics",
|
4483 |
+
"other_name": "",
|
4484 |
+
"required_fields": []
|
4485 |
+
},
|
4486 |
+
{
|
4487 |
+
"slug": "westbank-courier",
|
4488 |
+
"name": "West Bank Courier",
|
4489 |
+
"other_name": "",
|
4490 |
+
"required_fields": []
|
4491 |
+
},
|
4492 |
+
{
|
4493 |
+
"slug": "whistl",
|
4494 |
+
"name": "Whistl",
|
4495 |
+
"other_name": "",
|
4496 |
+
"required_fields": []
|
4497 |
+
},
|
4498 |
+
{
|
4499 |
+
"slug": "wise-express",
|
4500 |
+
"name": "Wise Express",
|
4501 |
+
"other_name": "u4e07u8272u901fu9012",
|
4502 |
+
"required_fields": []
|
4503 |
+
},
|
4504 |
+
{
|
4505 |
+
"slug": "wiseloads",
|
4506 |
+
"name": "Wiseloads",
|
4507 |
+
"other_name": "",
|
4508 |
+
"required_fields": []
|
4509 |
+
},
|
4510 |
+
{
|
4511 |
+
"slug": "wishpost",
|
4512 |
+
"name": "WishPost",
|
4513 |
+
"other_name": "Wish",
|
4514 |
+
"required_fields": []
|
4515 |
+
},
|
4516 |
+
{
|
4517 |
+
"slug": "wizmo",
|
4518 |
+
"name": "Wizmo",
|
4519 |
+
"other_name": "",
|
4520 |
+
"required_fields": []
|
4521 |
+
},
|
4522 |
+
{
|
4523 |
+
"slug": "wmg",
|
4524 |
+
"name": "WMG Delivery",
|
4525 |
+
"other_name": "World Marketing Group Pte Ltd",
|
4526 |
+
"required_fields": []
|
4527 |
+
},
|
4528 |
+
{
|
4529 |
+
"slug": "wndirect",
|
4530 |
+
"name": "wnDirect",
|
4531 |
+
"other_name": "",
|
4532 |
+
"required_fields": []
|
4533 |
+
},
|
4534 |
+
{
|
4535 |
+
"slug": "xdp-uk",
|
4536 |
+
"name": "XDP Express",
|
4537 |
+
"other_name": "XDP UK",
|
4538 |
+
"required_fields": [
|
4539 |
+
"tracking_postal_code"
|
4540 |
+
]
|
4541 |
+
},
|
4542 |
+
{
|
4543 |
+
"slug": "xdp-uk-reference",
|
4544 |
+
"name": "XDP Express Reference",
|
4545 |
+
"other_name": "XDP UK",
|
4546 |
+
"required_fields": [
|
4547 |
+
"tracking_postal_code"
|
4548 |
+
]
|
4549 |
+
},
|
4550 |
+
{
|
4551 |
+
"slug": "xend",
|
4552 |
+
"name": "Xend Express",
|
4553 |
+
"other_name": "Xend Business Solutions",
|
4554 |
+
"required_fields": []
|
4555 |
+
},
|
4556 |
+
{
|
4557 |
+
"slug": "xl-express",
|
4558 |
+
"name": "XL Express",
|
4559 |
+
"other_name": "",
|
4560 |
+
"required_fields": []
|
4561 |
+
},
|
4562 |
+
{
|
4563 |
+
"slug": "xpedigo",
|
4564 |
+
"name": "Xpedigo",
|
4565 |
+
"other_name": "",
|
4566 |
+
"required_fields": []
|
4567 |
+
},
|
4568 |
+
{
|
4569 |
+
"slug": "xpert-delivery",
|
4570 |
+
"name": "Xpert Delivery",
|
4571 |
+
"other_name": "",
|
4572 |
+
"required_fields": []
|
4573 |
+
},
|
4574 |
+
{
|
4575 |
+
"slug": "xpo-logistics",
|
4576 |
+
"name": "XPO logistics",
|
4577 |
+
"other_name": "",
|
4578 |
+
"required_fields": []
|
4579 |
+
},
|
4580 |
+
{
|
4581 |
+
"slug": "xpost",
|
4582 |
+
"name": "Xpost.ph",
|
4583 |
+
"other_name": "",
|
4584 |
+
"required_fields": []
|
4585 |
+
},
|
4586 |
+
{
|
4587 |
+
"slug": "xpressbees",
|
4588 |
+
"name": "XpressBees",
|
4589 |
+
"other_name": "XpressBees logistics",
|
4590 |
+
"required_fields": []
|
4591 |
+
},
|
4592 |
+
{
|
4593 |
+
"slug": "xq-express",
|
4594 |
+
"name": "XQ Express",
|
4595 |
+
"other_name": "u661fu4e7eu7269u6d41",
|
4596 |
+
"required_fields": []
|
4597 |
+
},
|
4598 |
+
{
|
4599 |
+
"slug": "yakit",
|
4600 |
+
"name": "Yakit",
|
4601 |
+
"other_name": "",
|
4602 |
+
"required_fields": []
|
4603 |
+
},
|
4604 |
+
{
|
4605 |
+
"slug": "yamato-hk",
|
4606 |
+
"name": "Yamato Hong Kong Shipments",
|
4607 |
+
"other_name": null,
|
4608 |
+
"required_fields": []
|
4609 |
+
},
|
4610 |
+
{
|
4611 |
+
"slug": "yanwen",
|
4612 |
+
"name": "Yanwen",
|
4613 |
+
"other_name": "燕文物流",
|
4614 |
+
"required_fields": []
|
4615 |
+
},
|
4616 |
+
{
|
4617 |
+
"slug": "ydh-express",
|
4618 |
+
"name": "YDH express",
|
4619 |
+
"other_name": null,
|
4620 |
+
"required_fields": []
|
4621 |
+
},
|
4622 |
+
{
|
4623 |
+
"slug": "yodel",
|
4624 |
+
"name": "Yodel Domestic",
|
4625 |
+
"other_name": "Home Delivery Network Limited (HDNL)",
|
4626 |
+
"required_fields": []
|
4627 |
+
},
|
4628 |
+
{
|
4629 |
+
"slug": "yodel-international",
|
4630 |
+
"name": "Yodel International",
|
4631 |
+
"other_name": "Home Delivery Network, HDNL",
|
4632 |
+
"required_fields": []
|
4633 |
+
},
|
4634 |
+
{
|
4635 |
+
"slug": "yrc",
|
4636 |
+
"name": "YRC",
|
4637 |
+
"other_name": "YRC Freight",
|
4638 |
+
"required_fields": []
|
4639 |
+
},
|
4640 |
+
{
|
4641 |
+
"slug": "yto",
|
4642 |
+
"name": "YTO Express",
|
4643 |
+
"other_name": "u5706u901au901fu9012",
|
4644 |
+
"required_fields": []
|
4645 |
+
},
|
4646 |
+
{
|
4647 |
+
"slug": "yundaex",
|
4648 |
+
"name": "Yunda Express",
|
4649 |
+
"other_name": "韵达快递",
|
4650 |
+
"required_fields": []
|
4651 |
+
},
|
4652 |
+
{
|
4653 |
+
"slug": "yunexpress",
|
4654 |
+
"name": "Yun Express",
|
4655 |
+
"other_name": "云途物流",
|
4656 |
+
"required_fields": []
|
4657 |
+
},
|
4658 |
+
{
|
4659 |
+
"slug": "yurtici-kargo",
|
4660 |
+
"name": "Yurtici Kargo",
|
4661 |
+
"other_name": "",
|
4662 |
+
"required_fields": []
|
4663 |
+
},
|
4664 |
+
{
|
4665 |
+
"slug": "yycom",
|
4666 |
+
"name": "HUAHANG EXPRESS",
|
4667 |
+
"other_name": "华航吉运",
|
4668 |
+
"required_fields": []
|
4669 |
+
},
|
4670 |
+
{
|
4671 |
+
"slug": "zajil-express",
|
4672 |
+
"name": "Zajil Express Company",
|
4673 |
+
"other_name": "",
|
4674 |
+
"required_fields": []
|
4675 |
+
},
|
4676 |
+
{
|
4677 |
+
"slug": "zeleris",
|
4678 |
+
"name": "Zeleris",
|
4679 |
+
"other_name": "",
|
4680 |
+
"required_fields": []
|
4681 |
+
},
|
4682 |
+
{
|
4683 |
+
"slug": "zepto-express",
|
4684 |
+
"name": "ZeptoExpress",
|
4685 |
+
"other_name": "",
|
4686 |
+
"required_fields": []
|
4687 |
+
},
|
4688 |
+
{
|
4689 |
+
"slug": "ziingfinalmile",
|
4690 |
+
"name": "Ziing Final Mile Inc",
|
4691 |
+
"other_name": null,
|
4692 |
+
"required_fields": []
|
4693 |
+
},
|
4694 |
+
{
|
4695 |
+
"slug": "zinc",
|
4696 |
+
"name": "Zinc",
|
4697 |
+
"other_name": "",
|
4698 |
+
"required_fields": []
|
4699 |
+
},
|
4700 |
+
{
|
4701 |
+
"slug": "zjs-express",
|
4702 |
+
"name": "ZJS International",
|
4703 |
+
"other_name": "宅急送快運",
|
4704 |
+
"required_fields": []
|
4705 |
+
},
|
4706 |
+
{
|
4707 |
+
"slug": "zto-express",
|
4708 |
+
"name": "ZTO Express",
|
4709 |
+
"other_name": "",
|
4710 |
+
"required_fields": []
|
4711 |
+
},
|
4712 |
+
{
|
4713 |
+
"slug": "zyllem",
|
4714 |
+
"name": "Zyllem",
|
4715 |
+
"other_name": "RocketUncle",
|
4716 |
+
"required_fields": []
|
4717 |
+
}
|
4718 |
+
]
|
assets/js/index.js
ADDED
@@ -0,0 +1,12 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
(async => {
|
2 |
+
|
3 |
+
|
4 |
+
const couriers = require('./couriers.json');
|
5 |
+
|
6 |
+
for (const courier of couriers) {
|
7 |
+
if (courier.required_fields.length){
|
8 |
+
//console.log(courier.slug + '=>' + courier.required_fields.join(','))
|
9 |
+
console.log(courier.required_fields.join(','))
|
10 |
+
}
|
11 |
+
}
|
12 |
+
})()
|
assets/js/meta-box.js
ADDED
@@ -0,0 +1,279 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
jQuery(function ($) {
|
2 |
+
|
3 |
+
var aftership_items = {
|
4 |
+
|
5 |
+
// init Class
|
6 |
+
init: function () {
|
7 |
+
$('#woocommerce-aftership')
|
8 |
+
.on('click', 'a.delete-tracking', this.delete_tracking)
|
9 |
+
.on('click', 'a.edit-tracking', this.edit_tracking)
|
10 |
+
.on('click', 'button.button-show-form', this.show_form)
|
11 |
+
.on('click', 'button.button-save-form', this.save_form)
|
12 |
+
.on('click', 'button.button-cancel', this.cancel_form)
|
13 |
+
.on('input','p input:visible', this.handle_input_change)
|
14 |
+
.on('change', 'select', this.handle_input_change)
|
15 |
+
},
|
16 |
+
|
17 |
+
// When a user enters a new tracking item
|
18 |
+
save_form: function () {
|
19 |
+
|
20 |
+
if (!$('input#aftership_tracking_number').val()) {
|
21 |
+
return false;
|
22 |
+
}
|
23 |
+
|
24 |
+
if ($('#woocommerce-aftership div.tracking-item').length > 999) {
|
25 |
+
$('#aftership-tracking-form').block({
|
26 |
+
message: "Tracking items more than 999 !",
|
27 |
+
overlayCSS: {
|
28 |
+
background: '#fff',
|
29 |
+
opacity: 0.6,
|
30 |
+
}
|
31 |
+
});
|
32 |
+
setTimeout($('#aftership-tracking-form').unblock(), 2000);
|
33 |
+
return false;
|
34 |
+
}
|
35 |
+
var exist = false;
|
36 |
+
|
37 |
+
$('#woocommerce-aftership div.tracking-item').each(function () {
|
38 |
+
var slug = $('#aftership_tracking_slug').val();
|
39 |
+
var tracking_number = $('input#aftership_tracking_number').val();
|
40 |
+
// convert to string
|
41 |
+
// unexpected: data-tracking="123" => typeof data('tracking') output number
|
42 |
+
if ($(this).data('tracking')+'' === tracking_number && $(this).data('slug')+'' === slug ) {
|
43 |
+
exist = true;
|
44 |
+
return false;
|
45 |
+
}
|
46 |
+
});
|
47 |
+
|
48 |
+
if (exist) {
|
49 |
+
aftership_items.show_error()
|
50 |
+
return false;
|
51 |
+
}
|
52 |
+
|
53 |
+
var data = {
|
54 |
+
action: 'aftership_save_form',
|
55 |
+
order_id: woocommerce_admin_meta_boxes.post_id,
|
56 |
+
aftership_tracking_slug: $('#aftership_tracking_slug').val(),
|
57 |
+
aftership_tracking_number: $('input#aftership_tracking_number').val(),
|
58 |
+
aftership_tracking_id: $('input#aftership_tracking_id').val(),
|
59 |
+
aftership_tracking_account_number: $('input#aftership_tracking_account_number').val(),
|
60 |
+
aftership_tracking_key: $('input#aftership_tracking_key').val(),
|
61 |
+
aftership_tracking_postal_code: $('input#aftership_tracking_postal_code').val(),
|
62 |
+
aftership_tracking_ship_date: $('input#aftership_tracking_ship_date').val(),
|
63 |
+
aftership_tracking_destination_country: $('input#aftership_tracking_destination_country').val(),
|
64 |
+
aftership_tracking_state: $('input#aftership_tracking_state').val(),
|
65 |
+
security: $('#aftership_create_nonce').val()
|
66 |
+
};
|
67 |
+
|
68 |
+
|
69 |
+
$.post(woocommerce_admin_meta_boxes.ajax_url, data, function (response) {
|
70 |
+
$('#aftership-tracking-form').unblock();
|
71 |
+
if (response != '-1') {
|
72 |
+
$('#aftership-tracking-form').hide();
|
73 |
+
$('#woocommerce-aftership .show-form-btn-container').show();
|
74 |
+
aftership_items.reset_form();
|
75 |
+
aftership_items.refresh_items();
|
76 |
+
}
|
77 |
+
});
|
78 |
+
|
79 |
+
return false;
|
80 |
+
},
|
81 |
+
|
82 |
+
// Show the new tracking item form
|
83 |
+
show_form: function () {
|
84 |
+
$('#aftership-tracking-form').show();
|
85 |
+
$('#woocommerce-aftership .show-form-btn-container').hide();
|
86 |
+
},
|
87 |
+
|
88 |
+
cancel_form: function(e) {
|
89 |
+
e.preventDefault();
|
90 |
+
$('#aftership-tracking-form').hide();
|
91 |
+
$('#woocommerce-aftership .show-form-btn-container').show();
|
92 |
+
aftership_items.reset_form();
|
93 |
+
aftership_items.refresh_items();
|
94 |
+
aftership_items.reset_error();
|
95 |
+
},
|
96 |
+
|
97 |
+
// Delete a tracking item
|
98 |
+
edit_tracking: function () {
|
99 |
+
|
100 |
+
// if form is open, alert user will reset current form
|
101 |
+
if($("#aftership-tracking-form").is(':visible')) {
|
102 |
+
if(window.confirm('If you edit this shipment, all unsaved changes will be lost. Are you sure you want to continue?')) {
|
103 |
+
aftership_items.refresh_items();
|
104 |
+
aftership_items.reset_form();
|
105 |
+
} else {
|
106 |
+
return false;
|
107 |
+
}
|
108 |
+
}
|
109 |
+
|
110 |
+
var tracking_id = $(this).attr('rel');
|
111 |
+
|
112 |
+
$('#woocommerce-aftership').block({
|
113 |
+
message: null,
|
114 |
+
overlayCSS: {
|
115 |
+
background: '#fff',
|
116 |
+
opacity: 0.6
|
117 |
+
}
|
118 |
+
});
|
119 |
+
|
120 |
+
var data = {
|
121 |
+
action: 'aftership_get_item',
|
122 |
+
order_id: woocommerce_admin_meta_boxes.post_id,
|
123 |
+
tracking_id: tracking_id,
|
124 |
+
security: $('#aftership_get_nonce').val()
|
125 |
+
};
|
126 |
+
|
127 |
+
$.post(woocommerce_admin_meta_boxes.ajax_url, data, function (response) {
|
128 |
+
$('#woocommerce-aftership').unblock();
|
129 |
+
$('#tracking-item-' + tracking_id).remove();
|
130 |
+
$('#woocommerce-aftership .show-form-btn-container').hide();
|
131 |
+
$('#aftership-tracking-form').show();
|
132 |
+
if(!response.tracking_id) return;
|
133 |
+
$('p.aftership_tracking_key_field').hide();
|
134 |
+
$('p.aftership_tracking_account_number_field').hide();
|
135 |
+
$('p.aftership_tracking_postal_code_field').hide();
|
136 |
+
$('p.aftership_tracking_ship_date_field').hide();
|
137 |
+
$('p.aftership_tracking_destination_country_field').hide();
|
138 |
+
$('p.aftership_tracking_state_field').hide();
|
139 |
+
var required_fields_mapping = {
|
140 |
+
tracking_key: 'aftership_tracking_key',
|
141 |
+
tracking_account_number: 'aftership_tracking_account_number',
|
142 |
+
tracking_postal_code: 'aftership_tracking_postal_code',
|
143 |
+
tracking_ship_date: 'aftership_tracking_ship_date',
|
144 |
+
tracking_destination_country: 'aftership_tracking_destination_country',
|
145 |
+
tracking_state: 'aftership_tracking_state',
|
146 |
+
};
|
147 |
+
var additional_fields_mapping = {
|
148 |
+
tracking_key: 'key',
|
149 |
+
tracking_account_number: 'account_number',
|
150 |
+
tracking_postal_code: 'postal_code',
|
151 |
+
tracking_ship_date: 'ship_date',
|
152 |
+
tracking_destination_country: 'destination_country',
|
153 |
+
tracking_state: 'state',
|
154 |
+
};
|
155 |
+
$('#aftership_tracking_slug').val(response.slug).change();
|
156 |
+
$('input#aftership_tracking_number').val(response.tracking_number);
|
157 |
+
$('input#aftership_tracking_id').val(tracking_id);
|
158 |
+
var required_fields = response.courier.required_fields;
|
159 |
+
for (var field of required_fields) {
|
160 |
+
var field_name = required_fields_mapping[field];
|
161 |
+
$('p.' + field_name + '_field').show();
|
162 |
+
var additional_field_name = additional_fields_mapping[field];
|
163 |
+
var field_value = response.additional_fields[additional_field_name];
|
164 |
+
$('input#' + field_name).val(field_value);
|
165 |
+
}
|
166 |
+
aftership_items.handle_input_change();
|
167 |
+
});
|
168 |
+
|
169 |
+
|
170 |
+
return false;
|
171 |
+
},
|
172 |
+
|
173 |
+
// Delete a tracking item
|
174 |
+
delete_tracking: function () {
|
175 |
+
|
176 |
+
var tracking_id = $(this).attr('rel');
|
177 |
+
|
178 |
+
$('#tracking-item-' + tracking_id).block({
|
179 |
+
message: null,
|
180 |
+
overlayCSS: {
|
181 |
+
background: '#fff',
|
182 |
+
opacity: 0.6
|
183 |
+
}
|
184 |
+
});
|
185 |
+
|
186 |
+
var data = {
|
187 |
+
action: 'aftership_delete_item',
|
188 |
+
order_id: woocommerce_admin_meta_boxes.post_id,
|
189 |
+
tracking_id: tracking_id,
|
190 |
+
security: $('#aftership_delete_nonce').val()
|
191 |
+
};
|
192 |
+
|
193 |
+
$.post(woocommerce_admin_meta_boxes.ajax_url, data, function (response) {
|
194 |
+
$('#tracking-item-' + tracking_id).unblock();
|
195 |
+
if (response != '-1') {
|
196 |
+
$('#tracking-item-' + tracking_id).remove();
|
197 |
+
}
|
198 |
+
});
|
199 |
+
|
200 |
+
return false;
|
201 |
+
},
|
202 |
+
|
203 |
+
refresh_items: function () {
|
204 |
+
var data = {
|
205 |
+
action: 'aftership_get_items',
|
206 |
+
order_id: woocommerce_admin_meta_boxes.post_id,
|
207 |
+
security: $('#aftership_get_nonce').val()
|
208 |
+
};
|
209 |
+
|
210 |
+
$('#woocommerce-aftership').block({
|
211 |
+
message: null,
|
212 |
+
overlayCSS: {
|
213 |
+
background: '#fff',
|
214 |
+
opacity: 0.6
|
215 |
+
}
|
216 |
+
});
|
217 |
+
|
218 |
+
$.post(woocommerce_admin_meta_boxes.ajax_url, data, function (response) {
|
219 |
+
$('#woocommerce-aftership').unblock();
|
220 |
+
if (response != '-1') {
|
221 |
+
$('#woocommerce-aftership #tracking-items').html(response);
|
222 |
+
}
|
223 |
+
});
|
224 |
+
},
|
225 |
+
|
226 |
+
reset_form: function() {
|
227 |
+
$('#aftership_tracking_slug').prop('selectedIndex', 0).change();
|
228 |
+
$('input#aftership_tracking_number').val('');
|
229 |
+
$('input#aftership_tracking_id').val('');
|
230 |
+
$('input#aftership_tracking_account_number').val('');
|
231 |
+
$('input#aftership_tracking_key').val('');
|
232 |
+
$('input#aftership_tracking_postal_code').val('');
|
233 |
+
$('input#aftership_tracking_ship_date').val('');
|
234 |
+
$('input#aftership_tracking_destination_country').val('');
|
235 |
+
$('input#aftership_tracking_state').val('');
|
236 |
+
$("#aftership_tracking_slug").trigger("chosen:updated");
|
237 |
+
return false;
|
238 |
+
},
|
239 |
+
|
240 |
+
handle_input_change() {
|
241 |
+
let disable_btn = false;
|
242 |
+
if(!$('#woocommerce-aftership select').val()) {
|
243 |
+
disable_btn = true;
|
244 |
+
}
|
245 |
+
$('#woocommerce-aftership input:visible').each((index,item) => {
|
246 |
+
if(!$(item).val()) {
|
247 |
+
disable_btn = true;
|
248 |
+
}
|
249 |
+
})
|
250 |
+
if(disable_btn) {
|
251 |
+
$('#woocommerce-aftership button.button-save-form').attr('disabled','disabled')
|
252 |
+
} else {
|
253 |
+
$('#woocommerce-aftership button.button-save-form').removeAttr('disabled')
|
254 |
+
}
|
255 |
+
aftership_items.reset_error();
|
256 |
+
},
|
257 |
+
|
258 |
+
show_error() {
|
259 |
+
let input = $('input#aftership_tracking_number').get(0);
|
260 |
+
if(input.checkValidity() === true) {
|
261 |
+
input.setCustomValidity('This shipment has already been added.');
|
262 |
+
$(input).after($('<div>This shipment has already been added.</div>'));
|
263 |
+
}
|
264 |
+
// input.reportValidity();
|
265 |
+
},
|
266 |
+
|
267 |
+
reset_error() {
|
268 |
+
let input = $('input#aftership_tracking_number').get(0);
|
269 |
+
if(input.checkValidity() === false) {
|
270 |
+
input.setCustomValidity('');
|
271 |
+
$(input).next().remove();
|
272 |
+
}
|
273 |
+
}
|
274 |
+
}
|
275 |
+
|
276 |
+
aftership_items.init();
|
277 |
+
|
278 |
+
window.aftership_items_refresh = aftership_items.refresh_items;
|
279 |
+
});
|
assets/js/setting.js
CHANGED
@@ -1,11 +1,7 @@
|
|
1 |
jQuery(function () {
|
2 |
function set_aftership_tracking_provider(selected_couriers) {
|
3 |
var couriers = sort_couriers(get_couriers());
|
4 |
-
|
5 |
-
// console.log(couriers);
|
6 |
-
|
7 |
jQuery.each(couriers, function (key, courier) {
|
8 |
-
// console.log(courier.name);
|
9 |
var str = '<option ';
|
10 |
str += 'value="' + courier['slug'] + '" ';
|
11 |
if (selected_couriers.hasOwnProperty(courier['slug'])) {
|
@@ -20,53 +16,15 @@ jQuery(function () {
|
|
20 |
jQuery('#couriers_select').trigger('chosen:updated');
|
21 |
}
|
22 |
|
23 |
-
function set_track_message_demo(){
|
24 |
-
jQuery('#track_message_demo_1').html(
|
25 |
-
jQuery('#track_message_1').val() + 'UPS' +
|
26 |
-
'<br/>'+
|
27 |
-
jQuery('#track_message_2').val() + '1Z0X118A0324011613'
|
28 |
-
);
|
29 |
-
}
|
30 |
-
|
31 |
jQuery('#couriers_select').change(function () {
|
32 |
var couriers_select = jQuery('#couriers_select').val();
|
33 |
var value = (couriers_select) ? couriers_select.join(',') : '';
|
34 |
jQuery('#couriers').val(value);
|
35 |
});
|
36 |
|
37 |
-
jQuery('#plugin').change(function () {
|
38 |
-
if (jQuery(this).val() == 'aftership') {
|
39 |
-
jQuery('#couriers').parent().parent().show();
|
40 |
-
jQuery('#track_message_demo_1').parent().parent().show();
|
41 |
-
} else {
|
42 |
-
jQuery('#couriers').parent().parent().hide();
|
43 |
-
jQuery('#track_message_demo_1').parent().parent().hide();
|
44 |
-
}
|
45 |
-
});
|
46 |
-
|
47 |
if (jQuery('#couriers')) {
|
48 |
var couriers_select = jQuery('#couriers').val();
|
49 |
var couriers_select_array = (couriers_select) ? couriers_select.split(',') : [];
|
50 |
set_aftership_tracking_provider(couriers_select_array);
|
51 |
-
|
52 |
-
if (jQuery('#plugin').val() != 'aftership') {
|
53 |
-
jQuery('#couriers').parent().parent().hide();
|
54 |
-
}
|
55 |
}
|
56 |
-
|
57 |
-
if (jQuery('#track_message_demo_1')) {
|
58 |
-
set_track_message_demo();
|
59 |
-
|
60 |
-
if (jQuery('#plugin').val() != 'aftership') {
|
61 |
-
jQuery('#track_message_demo_1').parent().parent().hide();
|
62 |
-
}
|
63 |
-
}
|
64 |
-
|
65 |
-
jQuery('#track_message_1').keyup(function () {
|
66 |
-
set_track_message_demo();
|
67 |
-
});
|
68 |
-
|
69 |
-
jQuery('#track_message_2').keyup(function () {
|
70 |
-
set_track_message_demo();
|
71 |
-
});
|
72 |
});
|
1 |
jQuery(function () {
|
2 |
function set_aftership_tracking_provider(selected_couriers) {
|
3 |
var couriers = sort_couriers(get_couriers());
|
|
|
|
|
|
|
4 |
jQuery.each(couriers, function (key, courier) {
|
|
|
5 |
var str = '<option ';
|
6 |
str += 'value="' + courier['slug'] + '" ';
|
7 |
if (selected_couriers.hasOwnProperty(courier['slug'])) {
|
16 |
jQuery('#couriers_select').trigger('chosen:updated');
|
17 |
}
|
18 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
19 |
jQuery('#couriers_select').change(function () {
|
20 |
var couriers_select = jQuery('#couriers_select').val();
|
21 |
var value = (couriers_select) ? couriers_select.join(',') : '';
|
22 |
jQuery('#couriers').val(value);
|
23 |
});
|
24 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
25 |
if (jQuery('#couriers')) {
|
26 |
var couriers_select = jQuery('#couriers').val();
|
27 |
var couriers_select_array = (couriers_select) ? couriers_select.split(',') : [];
|
28 |
set_aftership_tracking_provider(couriers_select_array);
|
|
|
|
|
|
|
|
|
29 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
30 |
});
|
class-aftership-api.php
DELETED
@@ -1,188 +0,0 @@
|
|
1 |
-
<?php
|
2 |
-
/**
|
3 |
-
* AfterShip API
|
4 |
-
*
|
5 |
-
* Handles AfterShip-API endpoint requests
|
6 |
-
*
|
7 |
-
* @author AfterShip
|
8 |
-
* @category API
|
9 |
-
* @package AfterShip
|
10 |
-
* @since 1.0
|
11 |
-
*/
|
12 |
-
|
13 |
-
if (!defined('ABSPATH')) exit; // Exit if accessed directly
|
14 |
-
|
15 |
-
class AfterShip_API
|
16 |
-
{
|
17 |
-
|
18 |
-
/** This is the major version for the REST API and takes
|
19 |
-
* first-order position in endpoint URLs
|
20 |
-
*/
|
21 |
-
const VERSION = 1;
|
22 |
-
|
23 |
-
/** @var WC_API_Server the REST API server */
|
24 |
-
public $server;
|
25 |
-
|
26 |
-
/**
|
27 |
-
* Setup class
|
28 |
-
*
|
29 |
-
* @access public
|
30 |
-
* @since 2.0
|
31 |
-
* @return WC_API
|
32 |
-
*/
|
33 |
-
public function __construct()
|
34 |
-
{
|
35 |
-
// disable notice output in api json response
|
36 |
-
error_reporting(0);
|
37 |
-
|
38 |
-
// add query vars
|
39 |
-
add_filter('query_vars', array($this, 'add_query_vars'), 0);
|
40 |
-
|
41 |
-
// register API endpoints
|
42 |
-
add_action('init', array($this, 'add_endpoint'), 0);
|
43 |
-
|
44 |
-
// handle REST/legacy API request
|
45 |
-
add_action('parse_request', array($this, 'handle_api_requests'), 0);
|
46 |
-
}
|
47 |
-
|
48 |
-
/**
|
49 |
-
* add_query_vars function.
|
50 |
-
*
|
51 |
-
* @access public
|
52 |
-
* @since 2.0
|
53 |
-
* @param $vars
|
54 |
-
* @return array
|
55 |
-
*/
|
56 |
-
public function add_query_vars($vars)
|
57 |
-
{
|
58 |
-
$vars[] = 'aftership-api';
|
59 |
-
$vars[] = 'aftership-api-route';
|
60 |
-
return $vars;
|
61 |
-
}
|
62 |
-
|
63 |
-
/**
|
64 |
-
* add_endpoint function.
|
65 |
-
*
|
66 |
-
* @access public
|
67 |
-
* @since 2.0
|
68 |
-
* @return void
|
69 |
-
*/
|
70 |
-
public function add_endpoint()
|
71 |
-
{
|
72 |
-
|
73 |
-
// REST API
|
74 |
-
add_rewrite_rule('^aftership-api\/v' . self::VERSION . '/?$', 'index.php?aftership-api-route=/', 'top');
|
75 |
-
add_rewrite_rule('^aftership-api\/v' . self::VERSION . '(.*)?', 'index.php?aftership-api-route=$matches[1]', 'top');
|
76 |
-
|
77 |
-
// legacy API for payment gateway IPNs
|
78 |
-
add_rewrite_endpoint('aftership-api', EP_ALL);
|
79 |
-
}
|
80 |
-
|
81 |
-
|
82 |
-
/**
|
83 |
-
* API request - Trigger any API requests
|
84 |
-
*
|
85 |
-
* @access public
|
86 |
-
* @since 2.0
|
87 |
-
* @return void
|
88 |
-
*/
|
89 |
-
public function handle_api_requests()
|
90 |
-
{
|
91 |
-
global $wp;
|
92 |
-
|
93 |
-
if (!empty($_GET['aftership-api']))
|
94 |
-
$wp->query_vars['aftership-api'] = $_GET['aftership-api'];
|
95 |
-
|
96 |
-
if (!empty($_GET['aftership-api-route']))
|
97 |
-
$wp->query_vars['aftership-api-route'] = $_GET['aftership-api-route'];
|
98 |
-
|
99 |
-
// REST API request
|
100 |
-
if (!empty($wp->query_vars['aftership-api-route'])) {
|
101 |
-
|
102 |
-
define('AFTERSHIP_API_REQUEST', true);
|
103 |
-
|
104 |
-
// load required files
|
105 |
-
$this->includes();
|
106 |
-
|
107 |
-
$this->server = new AfterShip_API_Server($wp->query_vars['aftership-api-route']);
|
108 |
-
|
109 |
-
// load API resource classes
|
110 |
-
$this->register_resources($this->server);
|
111 |
-
|
112 |
-
// Fire off the request
|
113 |
-
$this->server->serve_request();
|
114 |
-
|
115 |
-
exit;
|
116 |
-
}
|
117 |
-
|
118 |
-
// legacy API requests
|
119 |
-
if (!empty($wp->query_vars['aftership-api'])) {
|
120 |
-
|
121 |
-
// Buffer, we won't want any output here
|
122 |
-
ob_start();
|
123 |
-
|
124 |
-
// Get API trigger
|
125 |
-
$api = strtolower(esc_attr($wp->query_vars['aftership-api']));
|
126 |
-
|
127 |
-
// Load class if exists
|
128 |
-
if (class_exists($api))
|
129 |
-
$api_class = new $api();
|
130 |
-
|
131 |
-
// Trigger actions
|
132 |
-
do_action('woocommerce_api_' . $api);
|
133 |
-
|
134 |
-
// Done, clear buffer and exit
|
135 |
-
ob_end_clean();
|
136 |
-
die('1');
|
137 |
-
}
|
138 |
-
}
|
139 |
-
|
140 |
-
|
141 |
-
/**
|
142 |
-
* Include required files for REST API request
|
143 |
-
*
|
144 |
-
* @since 2.1
|
145 |
-
*/
|
146 |
-
private function includes()
|
147 |
-
{
|
148 |
-
|
149 |
-
// API server / response handlers
|
150 |
-
include_once('api/class-aftership-api-server.php');
|
151 |
-
include_once('api/interface-aftership-api-handler.php');
|
152 |
-
include_once('api/class-aftership-api-json-handler.php');
|
153 |
-
include_once('api/class-aftership-api-common-json-handler.php');
|
154 |
-
|
155 |
-
// authentication
|
156 |
-
include_once('api/class-aftership-api-authentication.php');
|
157 |
-
$this->authentication = new AfterShip_API_Authentication();
|
158 |
-
|
159 |
-
include_once('api/class-aftership-api-resource.php');
|
160 |
-
|
161 |
-
// self api
|
162 |
-
include_once('api/class-aftership-api-orders.php');
|
163 |
-
include_once('api/class-aftership-api-v3-orders.php');
|
164 |
-
|
165 |
-
}
|
166 |
-
|
167 |
-
/**
|
168 |
-
* Register available API resources
|
169 |
-
*
|
170 |
-
* @since 2.1
|
171 |
-
* @param object $server the REST server
|
172 |
-
*/
|
173 |
-
public function register_resources($server)
|
174 |
-
{
|
175 |
-
|
176 |
-
$api_classes = apply_filters('aftership_api_classes',
|
177 |
-
array(
|
178 |
-
'AfterShip_API_Orders',
|
179 |
-
'AfterShip_API_V3_Orders',
|
180 |
-
)
|
181 |
-
);
|
182 |
-
|
183 |
-
foreach ($api_classes as $api_class) {
|
184 |
-
$this->$api_class = new $api_class($server);
|
185 |
-
}
|
186 |
-
}
|
187 |
-
|
188 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class-aftership-dependencies.php
DELETED
@@ -1,35 +0,0 @@
|
|
1 |
-
<?php
|
2 |
-
class AfterShip_Dependencies {
|
3 |
-
|
4 |
-
private static $active_plugins;
|
5 |
-
|
6 |
-
public static function init() {
|
7 |
-
|
8 |
-
self::$active_plugins = (array) get_option( 'active_plugins', array() );
|
9 |
-
|
10 |
-
if ( is_multisite() )
|
11 |
-
self::$active_plugins = array_merge( self::$active_plugins, get_site_option( 'active_sitewide_plugins', array() ) );
|
12 |
-
}
|
13 |
-
|
14 |
-
public static function plugin_active_check($plugin){
|
15 |
-
if ( ! self::$active_plugins ) self::init();
|
16 |
-
if (is_array($plugin)) {
|
17 |
-
foreach ($plugin as $path) {
|
18 |
-
if (in_array( $path, self::$active_plugins ) || array_key_exists( $path, self::$active_plugins )) {
|
19 |
-
return true;
|
20 |
-
}
|
21 |
-
}
|
22 |
-
return false;
|
23 |
-
} else {
|
24 |
-
return in_array( $plugin, self::$active_plugins ) || array_key_exists( $plugin, self::$active_plugins );
|
25 |
-
}
|
26 |
-
|
27 |
-
}
|
28 |
-
|
29 |
-
public static function woocommerce_active_check() {
|
30 |
-
return self::plugin_active_check('woocommerce/woocommerce.php');
|
31 |
-
}
|
32 |
-
|
33 |
-
}
|
34 |
-
|
35 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class-aftership-settings.php
DELETED
@@ -1,295 +0,0 @@
|
|
1 |
-
<?php
|
2 |
-
/**
|
3 |
-
* AfterShip Admin
|
4 |
-
*
|
5 |
-
* Handles AfterShip-Admin endpoint requests
|
6 |
-
*
|
7 |
-
* @author AfterShip
|
8 |
-
* @category Admin
|
9 |
-
* @package AfterShip
|
10 |
-
* @since 1.0
|
11 |
-
*/
|
12 |
-
|
13 |
-
if (!defined('ABSPATH')) exit; // Exit if accessed directly
|
14 |
-
|
15 |
-
/**
|
16 |
-
* Required functions
|
17 |
-
*/
|
18 |
-
if (!class_exists('AfterShip_Dependencies'))
|
19 |
-
require_once 'class-aftership-dependencies.php';
|
20 |
-
|
21 |
-
class AfterShip_Settings
|
22 |
-
{
|
23 |
-
/**
|
24 |
-
* Holds the values to be used in the fields callbacks
|
25 |
-
*/
|
26 |
-
private $options;
|
27 |
-
|
28 |
-
private $plugins;
|
29 |
-
|
30 |
-
/**
|
31 |
-
* Start up
|
32 |
-
*/
|
33 |
-
public function __construct()
|
34 |
-
{
|
35 |
-
$this->plugins[] = array(
|
36 |
-
'value' => 'aftership',
|
37 |
-
'label' => 'AfterShip',
|
38 |
-
'path' => 'aftership-woocommerce-tracking/aftership.php'
|
39 |
-
);
|
40 |
-
$this->plugins[] = array(
|
41 |
-
'value' => 'wc-shipment-tracking',
|
42 |
-
'label' => 'WooCommerce Shipment Tracking',
|
43 |
-
'path' => array('woocommerce-shipment-tracking/shipment-tracking.php', 'woocommerce-shipment-tracking/woocommerce-shipment-tracking.php')
|
44 |
-
);
|
45 |
-
|
46 |
-
add_action('admin_menu', array($this, 'add_plugin_page'));
|
47 |
-
add_action('admin_init', array($this, 'page_init'));
|
48 |
-
add_action('admin_print_styles', array($this, 'admin_styles'));
|
49 |
-
add_action('admin_print_scripts', array(&$this, 'library_scripts'));
|
50 |
-
}
|
51 |
-
|
52 |
-
|
53 |
-
public function admin_styles()
|
54 |
-
{
|
55 |
-
wp_enqueue_style('aftership_styles_chosen', plugins_url(basename(dirname(__FILE__))) . '/assets/plugin/chosen/chosen.min.css');
|
56 |
-
wp_enqueue_style('aftership_styles', plugins_url(basename(dirname(__FILE__))) . '/assets/css/admin.css');
|
57 |
-
}
|
58 |
-
|
59 |
-
public function library_scripts()
|
60 |
-
{
|
61 |
-
wp_enqueue_script('aftership_styles_chosen_jquery', plugins_url(basename(dirname(__FILE__))) . '/assets/plugin/chosen/chosen.jquery.min.js');
|
62 |
-
wp_enqueue_script('aftership_styles_chosen_proto', plugins_url(basename(dirname(__FILE__))) . '/assets/plugin/chosen/chosen.proto.min.js');
|
63 |
-
wp_enqueue_script('aftership_script_util', plugins_url(basename(dirname(__FILE__))) . '/assets/js/util.js');
|
64 |
-
wp_enqueue_script('aftership_script_couriers', plugins_url(basename(dirname(__FILE__))) . '/assets/js/couriers.js');
|
65 |
-
wp_enqueue_script('aftership_script_setting', plugins_url(basename(dirname(__FILE__))) . '/assets/js/setting.js');
|
66 |
-
}
|
67 |
-
|
68 |
-
/**
|
69 |
-
* Add options page
|
70 |
-
*/
|
71 |
-
public function add_plugin_page()
|
72 |
-
{
|
73 |
-
// This page will be under "Settings"
|
74 |
-
add_options_page(
|
75 |
-
'AfterShip Settings Admin',
|
76 |
-
'AfterShip',
|
77 |
-
'manage_options',
|
78 |
-
'aftership-setting-admin',
|
79 |
-
array($this, 'create_admin_page')
|
80 |
-
);
|
81 |
-
}
|
82 |
-
|
83 |
-
/**
|
84 |
-
* Options page callback
|
85 |
-
*/
|
86 |
-
public function create_admin_page()
|
87 |
-
{
|
88 |
-
// Set class property
|
89 |
-
$this->options = get_option('aftership_option_name');
|
90 |
-
?>
|
91 |
-
<div class="wrap">
|
92 |
-
<?php screen_icon(); ?>
|
93 |
-
<h2>AfterShip Settings</h2>
|
94 |
-
|
95 |
-
<form method="post" action="options.php">
|
96 |
-
<?php
|
97 |
-
// This prints out all hidden setting fields
|
98 |
-
settings_fields('aftership_option_group');
|
99 |
-
do_settings_sections('aftership-setting-admin');
|
100 |
-
submit_button();
|
101 |
-
?>
|
102 |
-
</form>
|
103 |
-
</div>
|
104 |
-
<?php
|
105 |
-
}
|
106 |
-
|
107 |
-
/**
|
108 |
-
* Register and add settings
|
109 |
-
*/
|
110 |
-
public function page_init()
|
111 |
-
{
|
112 |
-
register_setting(
|
113 |
-
'aftership_option_group', // Option group
|
114 |
-
'aftership_option_name', // Option name
|
115 |
-
array($this, 'sanitize') // Sanitize
|
116 |
-
);
|
117 |
-
|
118 |
-
add_settings_section(
|
119 |
-
'aftership_setting_section_id', // ID
|
120 |
-
'', // Title
|
121 |
-
array($this, 'print_section_info'), // Callback
|
122 |
-
'aftership-setting-admin' // Page
|
123 |
-
);
|
124 |
-
|
125 |
-
add_settings_field(
|
126 |
-
'plugin',
|
127 |
-
'Plugin',
|
128 |
-
array($this, 'plugin_callback'),
|
129 |
-
'aftership-setting-admin',
|
130 |
-
'aftership_setting_section_id'
|
131 |
-
);
|
132 |
-
|
133 |
-
add_settings_field(
|
134 |
-
'couriers',
|
135 |
-
'Couriers',
|
136 |
-
array($this, 'couriers_callback'),
|
137 |
-
'aftership-setting-admin',
|
138 |
-
'aftership_setting_section_id'
|
139 |
-
);
|
140 |
-
|
141 |
-
add_settings_field(
|
142 |
-
'use_track_button',
|
143 |
-
'Display Track Button at Order History Page',
|
144 |
-
array($this, 'track_button_callback'),
|
145 |
-
'aftership-setting-admin',
|
146 |
-
'aftership_setting_section_id'
|
147 |
-
);
|
148 |
-
|
149 |
-
add_settings_field(
|
150 |
-
'custom_domain',
|
151 |
-
'Display Tracking Information at Custom Domain',
|
152 |
-
array($this, 'custom_domain_callback'),
|
153 |
-
'aftership-setting-admin',
|
154 |
-
'aftership_setting_section_id'
|
155 |
-
);
|
156 |
-
|
157 |
-
add_settings_field(
|
158 |
-
'track_message',
|
159 |
-
'Content',
|
160 |
-
array($this, 'track_message_callback'),
|
161 |
-
'aftership-setting-admin',
|
162 |
-
'aftership_setting_section_id'
|
163 |
-
);
|
164 |
-
}
|
165 |
-
|
166 |
-
/**
|
167 |
-
* Sanitize each setting field as needed
|
168 |
-
*
|
169 |
-
* @param array $input Contains all settings fields as array keys
|
170 |
-
*/
|
171 |
-
public function sanitize($input)
|
172 |
-
{
|
173 |
-
$new_input = array();
|
174 |
-
|
175 |
-
if (isset($input['couriers'])) {
|
176 |
-
$new_input['couriers'] = sanitize_text_field($input['couriers']);
|
177 |
-
}
|
178 |
-
|
179 |
-
if (isset($input['custom_domain'])) {
|
180 |
-
$new_input['custom_domain'] = sanitize_text_field($input['custom_domain']);
|
181 |
-
}
|
182 |
-
|
183 |
-
if (isset($input['plugin'])) {
|
184 |
-
$new_input['plugin'] = sanitize_text_field($input['plugin']);
|
185 |
-
}
|
186 |
-
|
187 |
-
if (isset($input['track_message_1'])) {
|
188 |
-
$postfix = '';
|
189 |
-
if (substr($input['track_message_1'], -1) == ' ') {
|
190 |
-
$postfix = ' ';
|
191 |
-
}
|
192 |
-
$new_input['track_message_1'] = sanitize_text_field($input['track_message_1']) . $postfix;
|
193 |
-
}
|
194 |
-
|
195 |
-
if (isset($input['track_message_2'])) {
|
196 |
-
$postfix = '';
|
197 |
-
if (substr($input['track_message_2'], -1) == ' ') {
|
198 |
-
$postfix = ' ';
|
199 |
-
}
|
200 |
-
$new_input['track_message_2'] = sanitize_text_field($input['track_message_2']) . $postfix;
|
201 |
-
}
|
202 |
-
|
203 |
-
if (isset($input['use_track_button'])) {
|
204 |
-
$new_input['use_track_button'] = true;
|
205 |
-
}
|
206 |
-
|
207 |
-
return $new_input;
|
208 |
-
}
|
209 |
-
|
210 |
-
/**
|
211 |
-
* Print the Section text
|
212 |
-
*/
|
213 |
-
public function print_section_info()
|
214 |
-
{
|
215 |
-
//print 'Enter your settings below:';
|
216 |
-
}
|
217 |
-
|
218 |
-
public function couriers_callback()
|
219 |
-
{
|
220 |
-
|
221 |
-
$couriers = array();
|
222 |
-
if (isset($this->options['couriers'])) {
|
223 |
-
$couriers = explode(',', $this->options['couriers']);
|
224 |
-
}
|
225 |
-
|
226 |
-
// print_r($couriers);
|
227 |
-
echo '<select data-placeholder="Please select couriers" id="couriers_select" class="chosen-select " multiple style="width:100%">';
|
228 |
-
echo '</select>';
|
229 |
-
// echo '<br><a href="https://www.aftership.com/settings/courier" target="_blank">Update carrier list</a>';
|
230 |
-
echo '<input type="hidden" id="couriers" name="aftership_option_name[couriers]" value="' . implode(",", $couriers) . '"/>';
|
231 |
-
|
232 |
-
}
|
233 |
-
|
234 |
-
public function plugin_callback()
|
235 |
-
{
|
236 |
-
|
237 |
-
$options = "";
|
238 |
-
foreach ($this->plugins as $plugin) {
|
239 |
-
//print_r($plugin);
|
240 |
-
if (AfterShip_Dependencies::plugin_active_check($plugin['path'])) {
|
241 |
-
$option = '<option value="' . $plugin['value'] . '"';
|
242 |
-
|
243 |
-
if (isset($this->options['plugin']) && esc_attr($this->options['plugin']) == $plugin['value']) {
|
244 |
-
$option .= ' selected="selected"';
|
245 |
-
}
|
246 |
-
|
247 |
-
$option .= '>' . $plugin['label'] . '</option>';
|
248 |
-
$options .= $option;
|
249 |
-
}
|
250 |
-
}
|
251 |
-
|
252 |
-
printf(
|
253 |
-
'<select id="plugin" name="aftership_option_name[plugin]" class="aftership_dropdown">' . $options . '</select>'
|
254 |
-
);
|
255 |
-
}
|
256 |
-
|
257 |
-
public function custom_domain_callback()
|
258 |
-
{
|
259 |
-
printf(
|
260 |
-
'<input type="text" id="custom_domain" name="aftership_option_name[custom_domain]" value="%s" style="width:100%%">',
|
261 |
-
isset($this->options['custom_domain']) ? $this->options['custom_domain'] : 'track.aftership.com'
|
262 |
-
);
|
263 |
-
}
|
264 |
-
|
265 |
-
public function track_message_callback()
|
266 |
-
{
|
267 |
-
printf(
|
268 |
-
'<input type="text" id="track_message_1" name="aftership_option_name[track_message_1]" value="%s" style="width:100%%">',
|
269 |
-
isset($this->options['track_message_1']) ? $this->options['track_message_1'] : 'Your order was shipped via '
|
270 |
-
);
|
271 |
-
printf('<br/>');
|
272 |
-
printf(
|
273 |
-
'<input type="text" id="track_message_2" name="aftership_option_name[track_message_2]" value="%s" style="width:100%%">',
|
274 |
-
isset($this->options['track_message_2']) ? $this->options['track_message_2'] : 'Tracking number is '
|
275 |
-
);
|
276 |
-
printf('<br/>');
|
277 |
-
printf('<br/>');
|
278 |
-
printf('<b>Demo:</b>');
|
279 |
-
printf(
|
280 |
-
'<div id="track_message_demo_1" style="width:100%%"></div>'
|
281 |
-
);
|
282 |
-
}
|
283 |
-
|
284 |
-
public function track_button_callback()
|
285 |
-
{
|
286 |
-
printf(
|
287 |
-
'<label><input type="checkbox" id="use_track_button" name="aftership_option_name[use_track_button]" %s>Use Track Button</label>',
|
288 |
-
(isset($this->options['use_track_button']) && $this->options['use_track_button'] === true) ? 'checked="checked"' : ''
|
289 |
-
);
|
290 |
-
}
|
291 |
-
}
|
292 |
-
|
293 |
-
|
294 |
-
if (is_admin())
|
295 |
-
$aftership_settings = new AfterShip_Settings();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
composer.json
ADDED
@@ -0,0 +1,8 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
{
|
2 |
+
"require-dev": {
|
3 |
+
"squizlabs/php_codesniffer": "3.*",
|
4 |
+
"woocommerce/woocommerce-sniffs": "^0.1.0",
|
5 |
+
"ccinn/composer-husky-plugin": "^0.1.0",
|
6 |
+
"ccinn/husky-php": "^0.1.0"
|
7 |
+
}
|
8 |
+
}
|
composer.lock
ADDED
@@ -0,0 +1,1991 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
{
|
2 |
+
"_readme": [
|
3 |
+
"This file locks the dependencies of your project to a known state",
|
4 |
+
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
5 |
+
"This file is @generated automatically"
|
6 |
+
],
|
7 |
+
"content-hash": "dd20b87eae148de4a7b552398c7bbcdf",
|
8 |
+
"packages": [],
|
9 |
+
"packages-dev": [
|
10 |
+
{
|
11 |
+
"name": "ccinn/composer-husky-plugin",
|
12 |
+
"version": "v0.1.0",
|
13 |
+
"source": {
|
14 |
+
"type": "git",
|
15 |
+
"url": "https://github.com/whiteCcinn/composer-husky-plugin.git",
|
16 |
+
"reference": "51816a336d7af168ccb021d4dc12cb5d3ae1e67b"
|
17 |
+
},
|
18 |
+
"dist": {
|
19 |
+
"type": "zip",
|
20 |
+
"url": "https://api.github.com/repos/whiteCcinn/composer-husky-plugin/zipball/51816a336d7af168ccb021d4dc12cb5d3ae1e67b",
|
21 |
+
"reference": "51816a336d7af168ccb021d4dc12cb5d3ae1e67b",
|
22 |
+
"shasum": ""
|
23 |
+
},
|
24 |
+
"require": {
|
25 |
+
"composer-plugin-api": "^1.1",
|
26 |
+
"ext-json": "*"
|
27 |
+
},
|
28 |
+
"require-dev": {
|
29 |
+
"composer/composer": "^1.6.5 || ^1.7.0 || ^1.8.0"
|
30 |
+
},
|
31 |
+
"type": "composer-plugin",
|
32 |
+
"extra": {
|
33 |
+
"class": "Husky\\Plugins\\HuskyPlugin"
|
34 |
+
},
|
35 |
+
"autoload": {
|
36 |
+
"psr-4": {
|
37 |
+
"Husky\\": "src/"
|
38 |
+
}
|
39 |
+
},
|
40 |
+
"notification-url": "https://packagist.org/downloads/",
|
41 |
+
"authors": [
|
42 |
+
{
|
43 |
+
"name": "caiwenhui",
|
44 |
+
"email": "471113744@qq.com",
|
45 |
+
"homepage": "https://github.com/whiteCcinn",
|
46 |
+
"role": "Developer"
|
47 |
+
}
|
48 |
+
],
|
49 |
+
"description": "Husky-php composer plugin",
|
50 |
+
"keywords": [
|
51 |
+
"composer-husky-plugin",
|
52 |
+
"composer-plugin",
|
53 |
+
"husky-php"
|
54 |
+
],
|
55 |
+
"time": "2019-05-09T03:19:36+00:00"
|
56 |
+
},
|
57 |
+
{
|
58 |
+
"name": "ccinn/husky-php",
|
59 |
+
"version": "v0.1.0",
|
60 |
+
"source": {
|
61 |
+
"type": "git",
|
62 |
+
"url": "https://github.com/whiteCcinn/husky-php.git",
|
63 |
+
"reference": "e42713a925c6c4eefb8d450aa1a5c7a724438cee"
|
64 |
+
},
|
65 |
+
"dist": {
|
66 |
+
"type": "zip",
|
67 |
+
"url": "https://api.github.com/repos/whiteCcinn/husky-php/zipball/e42713a925c6c4eefb8d450aa1a5c7a724438cee",
|
68 |
+
"reference": "e42713a925c6c4eefb8d450aa1a5c7a724438cee",
|
69 |
+
"shasum": ""
|
70 |
+
},
|
71 |
+
"require": {
|
72 |
+
"ccinn/php-cs-fixer-config": "^0.1.0",
|
73 |
+
"ext-json": "*",
|
74 |
+
"symfony/console": "~3.2",
|
75 |
+
"symfony/filesystem": "~3.4"
|
76 |
+
},
|
77 |
+
"bin": [
|
78 |
+
"husky-php",
|
79 |
+
"sh/husky-default-pre-commit"
|
80 |
+
],
|
81 |
+
"type": "library",
|
82 |
+
"autoload": {
|
83 |
+
"psr-4": {
|
84 |
+
"App\\": "src/"
|
85 |
+
}
|
86 |
+
},
|
87 |
+
"notification-url": "https://packagist.org/downloads/",
|
88 |
+
"authors": [
|
89 |
+
{
|
90 |
+
"name": "caiwenhui",
|
91 |
+
"email": "471113744@qq.com"
|
92 |
+
}
|
93 |
+
],
|
94 |
+
"description": "Similar to js-husky client git hook implementation",
|
95 |
+
"keywords": [
|
96 |
+
"husky",
|
97 |
+
"php"
|
98 |
+
],
|
99 |
+
"time": "2019-05-09T12:12:25+00:00"
|
100 |
+
},
|
101 |
+
{
|
102 |
+
"name": "ccinn/php-cs-fixer-config",
|
103 |
+
"version": "v0.1.0",
|
104 |
+
"source": {
|
105 |
+
"type": "git",
|
106 |
+
"url": "https://github.com/whiteCcinn/php-cs-fixer-config.git",
|
107 |
+
"reference": "0c9a9f61fea8bb589826e84b15bc376068382a8e"
|
108 |
+
},
|
109 |
+
"dist": {
|
110 |
+
"type": "zip",
|
111 |
+
"url": "https://api.github.com/repos/whiteCcinn/php-cs-fixer-config/zipball/0c9a9f61fea8bb589826e84b15bc376068382a8e",
|
112 |
+
"reference": "0c9a9f61fea8bb589826e84b15bc376068382a8e",
|
113 |
+
"shasum": ""
|
114 |
+
},
|
115 |
+
"require": {
|
116 |
+
"friendsofphp/php-cs-fixer": "^2.14.0",
|
117 |
+
"php": "^5.6 || ^7.0"
|
118 |
+
},
|
119 |
+
"bin": [
|
120 |
+
".php56_cs",
|
121 |
+
".php70_cs",
|
122 |
+
".php71_cs"
|
123 |
+
],
|
124 |
+
"type": "library",
|
125 |
+
"autoload": {
|
126 |
+
"psr-4": {
|
127 |
+
"PhpCsFixer\\Config\\": "src"
|
128 |
+
}
|
129 |
+
},
|
130 |
+
"notification-url": "https://packagist.org/downloads/",
|
131 |
+
"authors": [
|
132 |
+
{
|
133 |
+
"name": "caiwenhui",
|
134 |
+
"email": "471113744@qq.com",
|
135 |
+
"homepage": "https://github.com/whiteCcinn",
|
136 |
+
"role": "Developer"
|
137 |
+
}
|
138 |
+
],
|
139 |
+
"description": "php-cs-fixer-config",
|
140 |
+
"keywords": [
|
141 |
+
"php-cs-fixer-config"
|
142 |
+
],
|
143 |
+
"time": "2019-05-09T12:12:56+00:00"
|
144 |
+
},
|
145 |
+
{
|
146 |
+
"name": "composer/semver",
|
147 |
+
"version": "3.2.4",
|
148 |
+
"source": {
|
149 |
+
"type": "git",
|
150 |
+
"url": "https://github.com/composer/semver.git",
|
151 |
+
"reference": "a02fdf930a3c1c3ed3a49b5f63859c0c20e10464"
|
152 |
+
},
|
153 |
+
"dist": {
|
154 |
+
"type": "zip",
|
155 |
+
"url": "https://api.github.com/repos/composer/semver/zipball/a02fdf930a3c1c3ed3a49b5f63859c0c20e10464",
|
156 |
+
"reference": "a02fdf930a3c1c3ed3a49b5f63859c0c20e10464",
|
157 |
+
"shasum": ""
|
158 |
+
},
|
159 |
+
"require": {
|
160 |
+
"php": "^5.3.2 || ^7.0 || ^8.0"
|
161 |
+
},
|
162 |
+
"require-dev": {
|
163 |
+
"phpstan/phpstan": "^0.12.54",
|
164 |
+
"symfony/phpunit-bridge": "^4.2 || ^5"
|
165 |
+
},
|
166 |
+
"type": "library",
|
167 |
+
"extra": {
|
168 |
+
"branch-alias": {
|
169 |
+
"dev-main": "3.x-dev"
|
170 |
+
}
|
171 |
+
},
|
172 |
+
"autoload": {
|
173 |
+
"psr-4": {
|
174 |
+
"Composer\\Semver\\": "src"
|
175 |
+
}
|
176 |
+
},
|
177 |
+
"notification-url": "https://packagist.org/downloads/",
|
178 |
+
"license": [
|
179 |
+
"MIT"
|
180 |
+
],
|
181 |
+
"authors": [
|
182 |
+
{
|
183 |
+
"name": "Nils Adermann",
|
184 |
+
"email": "naderman@naderman.de",
|
185 |
+
"homepage": "http://www.naderman.de"
|
186 |
+
},
|
187 |
+
{
|
188 |
+
"name": "Jordi Boggiano",
|
189 |
+
"email": "j.boggiano@seld.be",
|
190 |
+
"homepage": "http://seld.be"
|
191 |
+
},
|
192 |
+
{
|
193 |
+
"name": "Rob Bast",
|
194 |
+
"email": "rob.bast@gmail.com",
|
195 |
+
"homepage": "http://robbast.nl"
|
196 |
+
}
|
197 |
+
],
|
198 |
+
"description": "Semver library that offers utilities, version constraint parsing and validation.",
|
199 |
+
"keywords": [
|
200 |
+
"semantic",
|
201 |
+
"semver",
|
202 |
+
"validation",
|
203 |
+
"versioning"
|
204 |
+
],
|
205 |
+
"time": "2020-11-13T08:59:24+00:00"
|
206 |
+
},
|
207 |
+
{
|
208 |
+
"name": "composer/xdebug-handler",
|
209 |
+
"version": "1.4.5",
|
210 |
+
"source": {
|
211 |
+
"type": "git",
|
212 |
+
"url": "https://github.com/composer/xdebug-handler.git",
|
213 |
+
"reference": "f28d44c286812c714741478d968104c5e604a1d4"
|
214 |
+
},
|
215 |
+
"dist": {
|
216 |
+
"type": "zip",
|
217 |
+
"url": "https://api.github.com/repos/composer/xdebug-handler/zipball/f28d44c286812c714741478d968104c5e604a1d4",
|
218 |
+
"reference": "f28d44c286812c714741478d968104c5e604a1d4",
|
219 |
+
"shasum": ""
|
220 |
+
},
|
221 |
+
"require": {
|
222 |
+
"php": "^5.3.2 || ^7.0 || ^8.0",
|
223 |
+
"psr/log": "^1.0"
|
224 |
+
},
|
225 |
+
"require-dev": {
|
226 |
+
"phpunit/phpunit": "^4.8.35 || ^5.7 || 6.5 - 8"
|
227 |
+
},
|
228 |
+
"type": "library",
|
229 |
+
"autoload": {
|
230 |
+
"psr-4": {
|
231 |
+
"Composer\\XdebugHandler\\": "src"
|
232 |
+
}
|
233 |
+
},
|
234 |
+
"notification-url": "https://packagist.org/downloads/",
|
235 |
+
"license": [
|
236 |
+
"MIT"
|
237 |
+
],
|
238 |
+
"authors": [
|
239 |
+
{
|
240 |
+
"name": "John Stevenson",
|
241 |
+
"email": "john-stevenson@blueyonder.co.uk"
|
242 |
+
}
|
243 |
+
],
|
244 |
+
"description": "Restarts a process without Xdebug.",
|
245 |
+
"keywords": [
|
246 |
+
"Xdebug",
|
247 |
+
"performance"
|
248 |
+
],
|
249 |
+
"time": "2020-11-13T08:04:11+00:00"
|
250 |
+
},
|
251 |
+
{
|
252 |
+
"name": "dealerdirect/phpcodesniffer-composer-installer",
|
253 |
+
"version": "v0.7.0",
|
254 |
+
"source": {
|
255 |
+
"type": "git",
|
256 |
+
"url": "https://github.com/Dealerdirect/phpcodesniffer-composer-installer.git",
|
257 |
+
"reference": "e8d808670b8f882188368faaf1144448c169c0b7"
|
258 |
+
},
|
259 |
+
"dist": {
|
260 |
+
"type": "zip",
|
261 |
+
"url": "https://api.github.com/repos/Dealerdirect/phpcodesniffer-composer-installer/zipball/e8d808670b8f882188368faaf1144448c169c0b7",
|
262 |
+
"reference": "e8d808670b8f882188368faaf1144448c169c0b7",
|
263 |
+
"shasum": ""
|
264 |
+
},
|
265 |
+
"require": {
|
266 |
+
"composer-plugin-api": "^1.0 || ^2.0",
|
267 |
+
"php": ">=5.3",
|
268 |
+
"squizlabs/php_codesniffer": "^2 || ^3 || 4.0.x-dev"
|
269 |
+
},
|
270 |
+
"require-dev": {
|
271 |
+
"composer/composer": "*",
|
272 |
+
"phpcompatibility/php-compatibility": "^9.0",
|
273 |
+
"sensiolabs/security-checker": "^4.1.0"
|
274 |
+
},
|
275 |
+
"type": "composer-plugin",
|
276 |
+
"extra": {
|
277 |
+
"class": "Dealerdirect\\Composer\\Plugin\\Installers\\PHPCodeSniffer\\Plugin"
|
278 |
+
},
|
279 |
+
"autoload": {
|
280 |
+
"psr-4": {
|
281 |
+
"Dealerdirect\\Composer\\Plugin\\Installers\\PHPCodeSniffer\\": "src/"
|
282 |
+
}
|
283 |
+
},
|
284 |
+
"notification-url": "https://packagist.org/downloads/",
|
285 |
+
"license": [
|
286 |
+
"MIT"
|
287 |
+
],
|
288 |
+
"authors": [
|
289 |
+
{
|
290 |
+
"name": "Franck Nijhof",
|
291 |
+
"email": "franck.nijhof@dealerdirect.com",
|
292 |
+
"homepage": "http://www.frenck.nl",
|
293 |
+
"role": "Developer / IT Manager"
|
294 |
+
}
|
295 |
+
],
|
296 |
+
"description": "PHP_CodeSniffer Standards Composer Installer Plugin",
|
297 |
+
"homepage": "http://www.dealerdirect.com",
|
298 |
+
"keywords": [
|
299 |
+
"PHPCodeSniffer",
|
300 |
+
"PHP_CodeSniffer",
|
301 |
+
"code quality",
|
302 |
+
"codesniffer",
|
303 |
+
"composer",
|
304 |
+
"installer",
|
305 |
+
"phpcs",
|
306 |
+
"plugin",
|
307 |
+
"qa",
|
308 |
+
"quality",
|
309 |
+
"standard",
|
310 |
+
"standards",
|
311 |
+
"style guide",
|
312 |
+
"stylecheck",
|
313 |
+
"tests"
|
314 |
+
],
|
315 |
+
"time": "2020-06-25T14:57:39+00:00"
|
316 |
+
},
|
317 |
+
{
|
318 |
+
"name": "doctrine/annotations",
|
319 |
+
"version": "1.12.1",
|
320 |
+
"source": {
|
321 |
+
"type": "git",
|
322 |
+
"url": "https://github.com/doctrine/annotations.git",
|
323 |
+
"reference": "b17c5014ef81d212ac539f07a1001832df1b6d3b"
|
324 |
+
},
|
325 |
+
"dist": {
|
326 |
+
"type": "zip",
|
327 |
+
"url": "https://api.github.com/repos/doctrine/annotations/zipball/b17c5014ef81d212ac539f07a1001832df1b6d3b",
|
328 |
+
"reference": "b17c5014ef81d212ac539f07a1001832df1b6d3b",
|
329 |
+
"shasum": ""
|
330 |
+
},
|
331 |
+
"require": {
|
332 |
+
"doctrine/lexer": "1.*",
|
333 |
+
"ext-tokenizer": "*",
|
334 |
+
"php": "^7.1 || ^8.0"
|
335 |
+
},
|
336 |
+
"require-dev": {
|
337 |
+
"doctrine/cache": "1.*",
|
338 |
+
"doctrine/coding-standard": "^6.0 || ^8.1",
|
339 |
+
"phpstan/phpstan": "^0.12.20",
|
340 |
+
"phpunit/phpunit": "^7.5 || ^9.1.5"
|
341 |
+
},
|
342 |
+
"type": "library",
|
343 |
+
"autoload": {
|
344 |
+
"psr-4": {
|
345 |
+
"Doctrine\\Common\\Annotations\\": "lib/Doctrine/Common/Annotations"
|
346 |
+
}
|
347 |
+
},
|
348 |
+
"notification-url": "https://packagist.org/downloads/",
|
349 |
+
"license": [
|
350 |
+
"MIT"
|
351 |
+
],
|
352 |
+
"authors": [
|
353 |
+
{
|
354 |
+
"name": "Guilherme Blanco",
|
355 |
+
"email": "guilhermeblanco@gmail.com"
|
356 |
+
},
|
357 |
+
{
|
358 |
+
"name": "Roman Borschel",
|
359 |
+
"email": "roman@code-factory.org"
|
360 |
+
},
|
361 |
+
{
|
362 |
+
"name": "Benjamin Eberlei",
|
363 |
+
"email": "kontakt@beberlei.de"
|
364 |
+
},
|
365 |
+
{
|
366 |
+
"name": "Jonathan Wage",
|
367 |
+
"email": "jonwage@gmail.com"
|
368 |
+
},
|
369 |
+
{
|
370 |
+
"name": "Johannes Schmitt",
|
371 |
+
"email": "schmittjoh@gmail.com"
|
372 |
+
}
|
373 |
+
],
|
374 |
+
"description": "Docblock Annotations Parser",
|
375 |
+
"homepage": "https://www.doctrine-project.org/projects/annotations.html",
|
376 |
+
"keywords": [
|
377 |
+
"annotations",
|
378 |
+
"docblock",
|
379 |
+
"parser"
|
380 |
+
],
|
381 |
+
"time": "2021-02-21T21:00:45+00:00"
|
382 |
+
},
|
383 |
+
{
|
384 |
+
"name": "doctrine/lexer",
|
385 |
+
"version": "1.2.1",
|
386 |
+
"source": {
|
387 |
+
"type": "git",
|
388 |
+
"url": "https://github.com/doctrine/lexer.git",
|
389 |
+
"reference": "e864bbf5904cb8f5bb334f99209b48018522f042"
|
390 |
+
},
|
391 |
+
"dist": {
|
392 |
+
"type": "zip",
|
393 |
+
"url": "https://api.github.com/repos/doctrine/lexer/zipball/e864bbf5904cb8f5bb334f99209b48018522f042",
|
394 |
+
"reference": "e864bbf5904cb8f5bb334f99209b48018522f042",
|
395 |
+
"shasum": ""
|
396 |
+
},
|
397 |
+
"require": {
|
398 |
+
"php": "^7.2 || ^8.0"
|
399 |
+
},
|
400 |
+
"require-dev": {
|
401 |
+
"doctrine/coding-standard": "^6.0",
|
402 |
+
"phpstan/phpstan": "^0.11.8",
|
403 |
+
"phpunit/phpunit": "^8.2"
|
404 |
+
},
|
405 |
+
"type": "library",
|
406 |
+
"extra": {
|
407 |
+
"branch-alias": {
|
408 |
+
"dev-master": "1.2.x-dev"
|
409 |
+
}
|
410 |
+
},
|
411 |
+
"autoload": {
|
412 |
+
"psr-4": {
|
413 |
+
"Doctrine\\Common\\Lexer\\": "lib/Doctrine/Common/Lexer"
|
414 |
+
}
|
415 |
+
},
|
416 |
+
"notification-url": "https://packagist.org/downloads/",
|
417 |
+
"license": [
|
418 |
+
"MIT"
|
419 |
+
],
|
420 |
+
"authors": [
|
421 |
+
{
|
422 |
+
"name": "Guilherme Blanco",
|
423 |
+
"email": "guilhermeblanco@gmail.com"
|
424 |
+
},
|
425 |
+
{
|
426 |
+
"name": "Roman Borschel",
|
427 |
+
"email": "roman@code-factory.org"
|
428 |
+
},
|
429 |
+
{
|
430 |
+
"name": "Johannes Schmitt",
|
431 |
+
"email": "schmittjoh@gmail.com"
|
432 |
+
}
|
433 |
+
],
|
434 |
+
"description": "PHP Doctrine Lexer parser library that can be used in Top-Down, Recursive Descent Parsers.",
|
435 |
+
"homepage": "https://www.doctrine-project.org/projects/lexer.html",
|
436 |
+
"keywords": [
|
437 |
+
"annotations",
|
438 |
+
"docblock",
|
439 |
+
"lexer",
|
440 |
+
"parser",
|
441 |
+
"php"
|
442 |
+
],
|
443 |
+
"time": "2020-05-25T17:44:05+00:00"
|
444 |
+
},
|
445 |
+
{
|
446 |
+
"name": "friendsofphp/php-cs-fixer",
|
447 |
+
"version": "v2.18.2",
|
448 |
+
"source": {
|
449 |
+
"type": "git",
|
450 |
+
"url": "https://github.com/FriendsOfPHP/PHP-CS-Fixer.git",
|
451 |
+
"reference": "18f8c9d184ba777380794a389fabc179896ba913"
|
452 |
+
},
|
453 |
+
"dist": {
|
454 |
+
"type": "zip",
|
455 |
+
"url": "https://api.github.com/repos/FriendsOfPHP/PHP-CS-Fixer/zipball/18f8c9d184ba777380794a389fabc179896ba913",
|
456 |
+
"reference": "18f8c9d184ba777380794a389fabc179896ba913",
|
457 |
+
"shasum": ""
|
458 |
+
},
|
459 |
+
"require": {
|
460 |
+
"composer/semver": "^1.4 || ^2.0 || ^3.0",
|
461 |
+
"composer/xdebug-handler": "^1.2",
|
462 |
+
"doctrine/annotations": "^1.2",
|
463 |
+
"ext-json": "*",
|
464 |
+
"ext-tokenizer": "*",
|
465 |
+
"php": "^5.6 || ^7.0 || ^8.0",
|
466 |
+
"php-cs-fixer/diff": "^1.3",
|
467 |
+
"symfony/console": "^3.4.43 || ^4.1.6 || ^5.0",
|
468 |
+
"symfony/event-dispatcher": "^3.0 || ^4.0 || ^5.0",
|
469 |
+
"symfony/filesystem": "^3.0 || ^4.0 || ^5.0",
|
470 |
+
"symfony/finder": "^3.0 || ^4.0 || ^5.0",
|
471 |
+
"symfony/options-resolver": "^3.0 || ^4.0 || ^5.0",
|
472 |
+
"symfony/polyfill-php70": "^1.0",
|
473 |
+
"symfony/polyfill-php72": "^1.4",
|
474 |
+
"symfony/process": "^3.0 || ^4.0 || ^5.0",
|
475 |
+
"symfony/stopwatch": "^3.0 || ^4.0 || ^5.0"
|
476 |
+
},
|
477 |
+
"require-dev": {
|
478 |
+
"justinrainbow/json-schema": "^5.0",
|
479 |
+
"keradus/cli-executor": "^1.4",
|
480 |
+
"mikey179/vfsstream": "^1.6",
|
481 |
+
"php-coveralls/php-coveralls": "^2.4.2",
|
482 |
+
"php-cs-fixer/accessible-object": "^1.0",
|
483 |
+
"php-cs-fixer/phpunit-constraint-isidenticalstring": "^1.2",
|
484 |
+
"php-cs-fixer/phpunit-constraint-xmlmatchesxsd": "^1.2.1",
|
485 |
+
"phpspec/prophecy-phpunit": "^1.1 || ^2.0",
|
486 |
+
"phpunit/phpunit": "^5.7.27 || ^6.5.14 || ^7.5.20 || ^8.5.13 || ^9.5",
|
487 |
+
"phpunitgoodpractices/polyfill": "^1.5",
|
488 |
+
"phpunitgoodpractices/traits": "^1.9.1",
|
489 |
+
"sanmai/phpunit-legacy-adapter": "^6.4 || ^8.2.1",
|
490 |
+
"symfony/phpunit-bridge": "^5.2.1",
|
491 |
+
"symfony/yaml": "^3.0 || ^4.0 || ^5.0"
|
492 |
+
},
|
493 |
+
"suggest": {
|
494 |
+
"ext-dom": "For handling output formats in XML",
|
495 |
+
"ext-mbstring": "For handling non-UTF8 characters.",
|
496 |
+
"php-cs-fixer/phpunit-constraint-isidenticalstring": "For IsIdenticalString constraint.",
|
497 |
+
"php-cs-fixer/phpunit-constraint-xmlmatchesxsd": "For XmlMatchesXsd constraint.",
|
498 |
+
"symfony/polyfill-mbstring": "When enabling `ext-mbstring` is not possible."
|
499 |
+
},
|
500 |
+
"bin": [
|
501 |
+
"php-cs-fixer"
|
502 |
+
],
|
503 |
+
"type": "application",
|
504 |
+
"autoload": {
|
505 |
+
"psr-4": {
|
506 |
+
"PhpCsFixer\\": "src/"
|
507 |
+
},
|
508 |
+
"classmap": [
|
509 |
+
"tests/Test/AbstractFixerTestCase.php",
|
510 |
+
"tests/Test/AbstractIntegrationCaseFactory.php",
|
511 |
+
"tests/Test/AbstractIntegrationTestCase.php",
|
512 |
+
"tests/Test/Assert/AssertTokensTrait.php",
|
513 |
+
"tests/Test/IntegrationCase.php",
|
514 |
+
"tests/Test/IntegrationCaseFactory.php",
|
515 |
+
"tests/Test/IntegrationCaseFactoryInterface.php",
|
516 |
+
"tests/Test/InternalIntegrationCaseFactory.php",
|
517 |
+
"tests/Test/IsIdenticalConstraint.php",
|
518 |
+
"tests/TestCase.php"
|
519 |
+
]
|
520 |
+
},
|
521 |
+
"notification-url": "https://packagist.org/downloads/",
|
522 |
+
"license": [
|
523 |
+
"MIT"
|
524 |
+
],
|
525 |
+
"authors": [
|
526 |
+
{
|
527 |
+
"name": "Fabien Potencier",
|
528 |
+
"email": "fabien@symfony.com"
|
529 |
+
},
|
530 |
+
{
|
531 |
+
"name": "Dariusz Rumiński",
|
532 |
+
"email": "dariusz.ruminski@gmail.com"
|
533 |
+
}
|
534 |
+
],
|
535 |
+
"description": "A tool to automatically fix PHP code style",
|
536 |
+
"time": "2021-01-26T00:22:21+00:00"
|
537 |
+
},
|
538 |
+
{
|
539 |
+
"name": "php-cs-fixer/diff",
|
540 |
+
"version": "v1.3.1",
|
541 |
+
"source": {
|
542 |
+
"type": "git",
|
543 |
+
"url": "https://github.com/PHP-CS-Fixer/diff.git",
|
544 |
+
"reference": "dbd31aeb251639ac0b9e7e29405c1441907f5759"
|
545 |
+
},
|
546 |
+
"dist": {
|
547 |
+
"type": "zip",
|
548 |
+
"url": "https://api.github.com/repos/PHP-CS-Fixer/diff/zipball/dbd31aeb251639ac0b9e7e29405c1441907f5759",
|
549 |
+
"reference": "dbd31aeb251639ac0b9e7e29405c1441907f5759",
|
550 |
+
"shasum": ""
|
551 |
+
},
|
552 |
+
"require": {
|
553 |
+
"php": "^5.6 || ^7.0 || ^8.0"
|
554 |
+
},
|
555 |
+
"require-dev": {
|
556 |
+
"phpunit/phpunit": "^5.7.23 || ^6.4.3 || ^7.0",
|
557 |
+
"symfony/process": "^3.3"
|
558 |
+
},
|
559 |
+
"type": "library",
|
560 |
+
"autoload": {
|
561 |
+
"classmap": [
|
562 |
+
"src/"
|
563 |
+
]
|
564 |
+
},
|
565 |
+
"notification-url": "https://packagist.org/downloads/",
|
566 |
+
"license": [
|
567 |
+
"BSD-3-Clause"
|
568 |
+
],
|
569 |
+
"authors": [
|
570 |
+
{
|
571 |
+
"name": "Sebastian Bergmann",
|
572 |
+
"email": "sebastian@phpunit.de"
|
573 |
+
},
|
574 |
+
{
|
575 |
+
"name": "Kore Nordmann",
|
576 |
+
"email": "mail@kore-nordmann.de"
|
577 |
+
},
|
578 |
+
{
|
579 |
+
"name": "SpacePossum"
|
580 |
+
}
|
581 |
+
],
|
582 |
+
"description": "sebastian/diff v2 backport support for PHP5.6",
|
583 |
+
"homepage": "https://github.com/PHP-CS-Fixer",
|
584 |
+
"keywords": [
|
585 |
+
"diff"
|
586 |
+
],
|
587 |
+
"time": "2020-10-14T08:39:05+00:00"
|
588 |
+
},
|
589 |
+
{
|
590 |
+
"name": "phpcompatibility/php-compatibility",
|
591 |
+
"version": "9.3.5",
|
592 |
+
"source": {
|
593 |
+
"type": "git",
|
594 |
+
"url": "https://github.com/PHPCompatibility/PHPCompatibility.git",
|
595 |
+
"reference": "9fb324479acf6f39452e0655d2429cc0d3914243"
|
596 |
+
},
|
597 |
+
"dist": {
|
598 |
+
"type": "zip",
|
599 |
+
"url": "https://api.github.com/repos/PHPCompatibility/PHPCompatibility/zipball/9fb324479acf6f39452e0655d2429cc0d3914243",
|
600 |
+
"reference": "9fb324479acf6f39452e0655d2429cc0d3914243",
|
601 |
+
"shasum": ""
|
602 |
+
},
|
603 |
+
"require": {
|
604 |
+
"php": ">=5.3",
|
605 |
+
"squizlabs/php_codesniffer": "^2.3 || ^3.0.2"
|
606 |
+
},
|
607 |
+
"conflict": {
|
608 |
+
"squizlabs/php_codesniffer": "2.6.2"
|
609 |
+
},
|
610 |
+
"require-dev": {
|
611 |
+
"phpunit/phpunit": "~4.5 || ^5.0 || ^6.0 || ^7.0"
|
612 |
+
},
|
613 |
+
"suggest": {
|
614 |
+
"dealerdirect/phpcodesniffer-composer-installer": "^0.5 || This Composer plugin will sort out the PHPCS 'installed_paths' automatically.",
|
615 |
+
"roave/security-advisories": "dev-master || Helps prevent installing dependencies with known security issues."
|
616 |
+
},
|
617 |
+
"type": "phpcodesniffer-standard",
|
618 |
+
"notification-url": "https://packagist.org/downloads/",
|
619 |
+
"license": [
|
620 |
+
"LGPL-3.0-or-later"
|
621 |
+
],
|
622 |
+
"authors": [
|
623 |
+
{
|
624 |
+
"name": "Wim Godden",
|
625 |
+
"homepage": "https://github.com/wimg",
|
626 |
+
"role": "lead"
|
627 |
+
},
|
628 |
+
{
|
629 |
+
"name": "Juliette Reinders Folmer",
|
630 |
+
"homepage": "https://github.com/jrfnl",
|
631 |
+
"role": "lead"
|
632 |
+
},
|
633 |
+
{
|
634 |
+
"name": "Contributors",
|
635 |
+
"homepage": "https://github.com/PHPCompatibility/PHPCompatibility/graphs/contributors"
|
636 |
+
}
|
637 |
+
],
|
638 |
+
"description": "A set of sniffs for PHP_CodeSniffer that checks for PHP cross-version compatibility.",
|
639 |
+
"homepage": "http://techblog.wimgodden.be/tag/codesniffer/",
|
640 |
+
"keywords": [
|
641 |
+
"compatibility",
|
642 |
+
"phpcs",
|
643 |
+
"standards"
|
644 |
+
],
|
645 |
+
"time": "2019-12-27T09:44:58+00:00"
|
646 |
+
},
|
647 |
+
{
|
648 |
+
"name": "phpcompatibility/phpcompatibility-paragonie",
|
649 |
+
"version": "1.3.1",
|
650 |
+
"source": {
|
651 |
+
"type": "git",
|
652 |
+
"url": "https://github.com/PHPCompatibility/PHPCompatibilityParagonie.git",
|
653 |
+
"reference": "ddabec839cc003651f2ce695c938686d1086cf43"
|
654 |
+
},
|
655 |
+
"dist": {
|
656 |
+
"type": "zip",
|
657 |
+
"url": "https://api.github.com/repos/PHPCompatibility/PHPCompatibilityParagonie/zipball/ddabec839cc003651f2ce695c938686d1086cf43",
|
658 |
+
"reference": "ddabec839cc003651f2ce695c938686d1086cf43",
|
659 |
+
"shasum": ""
|
660 |
+
},
|
661 |
+
"require": {
|
662 |
+
"phpcompatibility/php-compatibility": "^9.0"
|
663 |
+
},
|
664 |
+
"require-dev": {
|
665 |
+
"dealerdirect/phpcodesniffer-composer-installer": "^0.7",
|
666 |
+
"paragonie/random_compat": "dev-master",
|
667 |
+
"paragonie/sodium_compat": "dev-master"
|
668 |
+
},
|
669 |
+
"suggest": {
|
670 |
+
"dealerdirect/phpcodesniffer-composer-installer": "^0.7 || This Composer plugin will sort out the PHP_CodeSniffer 'installed_paths' automatically.",
|
671 |
+
"roave/security-advisories": "dev-master || Helps prevent installing dependencies with known security issues."
|
672 |
+
},
|
673 |
+
"type": "phpcodesniffer-standard",
|
674 |
+
"notification-url": "https://packagist.org/downloads/",
|
675 |
+
"license": [
|
676 |
+
"LGPL-3.0-or-later"
|
677 |
+
],
|
678 |
+
"authors": [
|
679 |
+
{
|
680 |
+
"name": "Wim Godden",
|
681 |
+
"role": "lead"
|
682 |
+
},
|
683 |
+
{
|
684 |
+
"name": "Juliette Reinders Folmer",
|
685 |
+
"role": "lead"
|
686 |
+
}
|
687 |
+
],
|
688 |
+
"description": "A set of rulesets for PHP_CodeSniffer to check for PHP cross-version compatibility issues in projects, while accounting for polyfills provided by the Paragonie polyfill libraries.",
|
689 |
+
"homepage": "http://phpcompatibility.com/",
|
690 |
+
"keywords": [
|
691 |
+
"compatibility",
|
692 |
+
"paragonie",
|
693 |
+
"phpcs",
|
694 |
+
"polyfill",
|
695 |
+
"standards"
|
696 |
+
],
|
697 |
+
"time": "2021-02-15T10:24:51+00:00"
|
698 |
+
},
|
699 |
+
{
|
700 |
+
"name": "phpcompatibility/phpcompatibility-wp",
|
701 |
+
"version": "2.1.0",
|
702 |
+
"source": {
|
703 |
+
"type": "git",
|
704 |
+
"url": "https://github.com/PHPCompatibility/PHPCompatibilityWP.git",
|
705 |
+
"reference": "41bef18ba688af638b7310666db28e1ea9158b2f"
|
706 |
+
},
|
707 |
+
"dist": {
|
708 |
+
"type": "zip",
|
709 |
+
"url": "https://api.github.com/repos/PHPCompatibility/PHPCompatibilityWP/zipball/41bef18ba688af638b7310666db28e1ea9158b2f",
|
710 |
+
"reference": "41bef18ba688af638b7310666db28e1ea9158b2f",
|
711 |
+
"shasum": ""
|
712 |
+
},
|
713 |
+
"require": {
|
714 |
+
"phpcompatibility/php-compatibility": "^9.0",
|
715 |
+
"phpcompatibility/phpcompatibility-paragonie": "^1.0"
|
716 |
+
},
|
717 |
+
"require-dev": {
|
718 |
+
"dealerdirect/phpcodesniffer-composer-installer": "^0.5"
|
719 |
+
},
|
720 |
+
"suggest": {
|
721 |
+
"dealerdirect/phpcodesniffer-composer-installer": "^0.5 || This Composer plugin will sort out the PHP_CodeSniffer 'installed_paths' automatically.",
|
722 |
+
"roave/security-advisories": "dev-master || Helps prevent installing dependencies with known security issues."
|
723 |
+
},
|
724 |
+
"type": "phpcodesniffer-standard",
|
725 |
+
"notification-url": "https://packagist.org/downloads/",
|
726 |
+
"license": [
|
727 |
+
"LGPL-3.0-or-later"
|
728 |
+
],
|
729 |
+
"authors": [
|
730 |
+
{
|
731 |
+
"name": "Wim Godden",
|
732 |
+
"role": "lead"
|
733 |
+
},
|
734 |
+
{
|
735 |
+
"name": "Juliette Reinders Folmer",
|
736 |
+
"role": "lead"
|
737 |
+
}
|
738 |
+
],
|
739 |
+
"description": "A ruleset for PHP_CodeSniffer to check for PHP cross-version compatibility issues in projects, while accounting for polyfills provided by WordPress.",
|
740 |
+
"homepage": "http://phpcompatibility.com/",
|
741 |
+
"keywords": [
|
742 |
+
"compatibility",
|
743 |
+
"phpcs",
|
744 |
+
"standards",
|
745 |
+
"wordpress"
|
746 |
+
],
|
747 |
+
"time": "2019-08-28T14:22:28+00:00"
|
748 |
+
},
|
749 |
+
{
|
750 |
+
"name": "psr/container",
|
751 |
+
"version": "1.0.0",
|
752 |
+
"source": {
|
753 |
+
"type": "git",
|
754 |
+
"url": "https://github.com/php-fig/container.git",
|
755 |
+
"reference": "b7ce3b176482dbbc1245ebf52b181af44c2cf55f"
|
756 |
+
},
|
757 |
+
"dist": {
|
758 |
+
"type": "zip",
|
759 |
+
"url": "https://api.github.com/repos/php-fig/container/zipball/b7ce3b176482dbbc1245ebf52b181af44c2cf55f",
|
760 |
+
"reference": "b7ce3b176482dbbc1245ebf52b181af44c2cf55f",
|
761 |
+
"shasum": ""
|
762 |
+
},
|
763 |
+
"require": {
|
764 |
+
"php": ">=5.3.0"
|
765 |
+
},
|
766 |
+
"type": "library",
|
767 |
+
"extra": {
|
768 |
+
"branch-alias": {
|
769 |
+
"dev-master": "1.0.x-dev"
|
770 |
+
}
|
771 |
+
},
|
772 |
+
"autoload": {
|
773 |
+
"psr-4": {
|
774 |
+
"Psr\\Container\\": "src/"
|
775 |
+
}
|
776 |
+
},
|
777 |
+
"notification-url": "https://packagist.org/downloads/",
|
778 |
+
"license": [
|
779 |
+
"MIT"
|
780 |
+
],
|
781 |
+
"authors": [
|
782 |
+
{
|
783 |
+
"name": "PHP-FIG",
|
784 |
+
"homepage": "http://www.php-fig.org/"
|
785 |
+
}
|
786 |
+
],
|
787 |
+
"description": "Common Container Interface (PHP FIG PSR-11)",
|
788 |
+
"homepage": "https://github.com/php-fig/container",
|
789 |
+
"keywords": [
|
790 |
+
"PSR-11",
|
791 |
+
"container",
|
792 |
+
"container-interface",
|
793 |
+
"container-interop",
|
794 |
+
"psr"
|
795 |
+
],
|
796 |
+
"time": "2017-02-14T16:28:37+00:00"
|
797 |
+
},
|
798 |
+
{
|
799 |
+
"name": "psr/event-dispatcher",
|
800 |
+
"version": "1.0.0",
|
801 |
+
"source": {
|
802 |
+
"type": "git",
|
803 |
+
"url": "https://github.com/php-fig/event-dispatcher.git",
|
804 |
+
"reference": "dbefd12671e8a14ec7f180cab83036ed26714bb0"
|
805 |
+
},
|
806 |
+
"dist": {
|
807 |
+
"type": "zip",
|
808 |
+
"url": "https://api.github.com/repos/php-fig/event-dispatcher/zipball/dbefd12671e8a14ec7f180cab83036ed26714bb0",
|
809 |
+
"reference": "dbefd12671e8a14ec7f180cab83036ed26714bb0",
|
810 |
+
"shasum": ""
|
811 |
+
},
|
812 |
+
"require": {
|
813 |
+
"php": ">=7.2.0"
|
814 |
+
},
|
815 |
+
"type": "library",
|
816 |
+
"extra": {
|
817 |
+
"branch-alias": {
|
818 |
+
"dev-master": "1.0.x-dev"
|
819 |
+
}
|
820 |
+
},
|
821 |
+
"autoload": {
|
822 |
+
"psr-4": {
|
823 |
+
"Psr\\EventDispatcher\\": "src/"
|
824 |
+
}
|
825 |
+
},
|
826 |
+
"notification-url": "https://packagist.org/downloads/",
|
827 |
+
"license": [
|
828 |
+
"MIT"
|
829 |
+
],
|
830 |
+
"authors": [
|
831 |
+
{
|
832 |
+
"name": "PHP-FIG",
|
833 |
+
"homepage": "http://www.php-fig.org/"
|
834 |
+
}
|
835 |
+
],
|
836 |
+
"description": "Standard interfaces for event handling.",
|
837 |
+
"keywords": [
|
838 |
+
"events",
|
839 |
+
"psr",
|
840 |
+
"psr-14"
|
841 |
+
],
|
842 |
+
"time": "2019-01-08T18:20:26+00:00"
|
843 |
+
},
|
844 |
+
{
|
845 |
+
"name": "psr/log",
|
846 |
+
"version": "1.1.3",
|
847 |
+
"source": {
|
848 |
+
"type": "git",
|
849 |
+
"url": "https://github.com/php-fig/log.git",
|
850 |
+
"reference": "0f73288fd15629204f9d42b7055f72dacbe811fc"
|
851 |
+
},
|
852 |
+
"dist": {
|
853 |
+
"type": "zip",
|
854 |
+
"url": "https://api.github.com/repos/php-fig/log/zipball/0f73288fd15629204f9d42b7055f72dacbe811fc",
|
855 |
+
"reference": "0f73288fd15629204f9d42b7055f72dacbe811fc",
|
856 |
+
"shasum": ""
|
857 |
+
},
|
858 |
+
"require": {
|
859 |
+
"php": ">=5.3.0"
|
860 |
+
},
|
861 |
+
"type": "library",
|
862 |
+
"extra": {
|
863 |
+
"branch-alias": {
|
864 |
+
"dev-master": "1.1.x-dev"
|
865 |
+
}
|
866 |
+
},
|
867 |
+
"autoload": {
|
868 |
+
"psr-4": {
|
869 |
+
"Psr\\Log\\": "Psr/Log/"
|
870 |
+
}
|
871 |
+
},
|
872 |
+
"notification-url": "https://packagist.org/downloads/",
|
873 |
+
"license": [
|
874 |
+
"MIT"
|
875 |
+
],
|
876 |
+
"authors": [
|
877 |
+
{
|
878 |
+
"name": "PHP-FIG",
|
879 |
+
"homepage": "http://www.php-fig.org/"
|
880 |
+
}
|
881 |
+
],
|
882 |
+
"description": "Common interface for logging libraries",
|
883 |
+
"homepage": "https://github.com/php-fig/log",
|
884 |
+
"keywords": [
|
885 |
+
"log",
|
886 |
+
"psr",
|
887 |
+
"psr-3"
|
888 |
+
],
|
889 |
+
"time": "2020-03-23T09:12:05+00:00"
|
890 |
+
},
|
891 |
+
{
|
892 |
+
"name": "squizlabs/php_codesniffer",
|
893 |
+
"version": "3.5.8",
|
894 |
+
"source": {
|
895 |
+
"type": "git",
|
896 |
+
"url": "https://github.com/squizlabs/PHP_CodeSniffer.git",
|
897 |
+
"reference": "9d583721a7157ee997f235f327de038e7ea6dac4"
|
898 |
+
},
|
899 |
+
"dist": {
|
900 |
+
"type": "zip",
|
901 |
+
"url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/9d583721a7157ee997f235f327de038e7ea6dac4",
|
902 |
+
"reference": "9d583721a7157ee997f235f327de038e7ea6dac4",
|
903 |
+
"shasum": ""
|
904 |
+
},
|
905 |
+
"require": {
|
906 |
+
"ext-simplexml": "*",
|
907 |
+
"ext-tokenizer": "*",
|
908 |
+
"ext-xmlwriter": "*",
|
909 |
+
"php": ">=5.4.0"
|
910 |
+
},
|
911 |
+
"require-dev": {
|
912 |
+
"phpunit/phpunit": "^4.0 || ^5.0 || ^6.0 || ^7.0"
|
913 |
+
},
|
914 |
+
"bin": [
|
915 |
+
"bin/phpcs",
|
916 |
+
"bin/phpcbf"
|
917 |
+
],
|
918 |
+
"type": "library",
|
919 |
+
"extra": {
|
920 |
+
"branch-alias": {
|
921 |
+
"dev-master": "3.x-dev"
|
922 |
+
}
|
923 |
+
},
|
924 |
+
"notification-url": "https://packagist.org/downloads/",
|
925 |
+
"license": [
|
926 |
+
"BSD-3-Clause"
|
927 |
+
],
|
928 |
+
"authors": [
|
929 |
+
{
|
930 |
+
"name": "Greg Sherwood",
|
931 |
+
"role": "lead"
|
932 |
+
}
|
933 |
+
],
|
934 |
+
"description": "PHP_CodeSniffer tokenizes PHP, JavaScript and CSS files and detects violations of a defined set of coding standards.",
|
935 |
+
"homepage": "https://github.com/squizlabs/PHP_CodeSniffer",
|
936 |
+
"keywords": [
|
937 |
+
"phpcs",
|
938 |
+
"standards"
|
939 |
+
],
|
940 |
+
"time": "2020-10-23T02:01:07+00:00"
|
941 |
+
},
|
942 |
+
{
|
943 |
+
"name": "symfony/console",
|
944 |
+
"version": "v3.4.47",
|
945 |
+
"source": {
|
946 |
+
"type": "git",
|
947 |
+
"url": "https://github.com/symfony/console.git",
|
948 |
+
"reference": "a10b1da6fc93080c180bba7219b5ff5b7518fe81"
|
949 |
+
},
|
950 |
+
"dist": {
|
951 |
+
"type": "zip",
|
952 |
+
"url": "https://api.github.com/repos/symfony/console/zipball/a10b1da6fc93080c180bba7219b5ff5b7518fe81",
|
953 |
+
"reference": "a10b1da6fc93080c180bba7219b5ff5b7518fe81",
|
954 |
+
"shasum": ""
|
955 |
+
},
|
956 |
+
"require": {
|
957 |
+
"php": "^5.5.9|>=7.0.8",
|
958 |
+
"symfony/debug": "~2.8|~3.0|~4.0",
|
959 |
+
"symfony/polyfill-mbstring": "~1.0"
|
960 |
+
},
|
961 |
+
"conflict": {
|
962 |
+
"symfony/dependency-injection": "<3.4",
|
963 |
+
"symfony/process": "<3.3"
|
964 |
+
},
|
965 |
+
"provide": {
|
966 |
+
"psr/log-implementation": "1.0"
|
967 |
+
},
|
968 |
+
"require-dev": {
|
969 |
+
"psr/log": "~1.0",
|
970 |
+
"symfony/config": "~3.3|~4.0",
|
971 |
+
"symfony/dependency-injection": "~3.4|~4.0",
|
972 |
+
"symfony/event-dispatcher": "~2.8|~3.0|~4.0",
|
973 |
+
"symfony/lock": "~3.4|~4.0",
|
974 |
+
"symfony/process": "~3.3|~4.0"
|
975 |
+
},
|
976 |
+
"suggest": {
|
977 |
+
"psr/log": "For using the console logger",
|
978 |
+
"symfony/event-dispatcher": "",
|
979 |
+
"symfony/lock": "",
|
980 |
+
"symfony/process": ""
|
981 |
+
},
|
982 |
+
"type": "library",
|
983 |
+
"autoload": {
|
984 |
+
"psr-4": {
|
985 |
+
"Symfony\\Component\\Console\\": ""
|
986 |
+
},
|
987 |
+
"exclude-from-classmap": [
|
988 |
+
"/Tests/"
|
989 |
+
]
|
990 |
+
},
|
991 |
+
"notification-url": "https://packagist.org/downloads/",
|
992 |
+
"license": [
|
993 |
+
"MIT"
|
994 |
+
],
|
995 |
+
"authors": [
|
996 |
+
{
|
997 |
+
"name": "Fabien Potencier",
|
998 |
+
"email": "fabien@symfony.com"
|
999 |
+
},
|
1000 |
+
{
|
1001 |
+
"name": "Symfony Community",
|
1002 |
+
"homepage": "https://symfony.com/contributors"
|
1003 |
+
}
|
1004 |
+
],
|
1005 |
+
"description": "Symfony Console Component",
|
1006 |
+
"homepage": "https://symfony.com",
|
1007 |
+
"time": "2020-10-24T10:57:07+00:00"
|
1008 |
+
},
|
1009 |
+
{
|
1010 |
+
"name": "symfony/debug",
|
1011 |
+
"version": "v4.4.19",
|
1012 |
+
"source": {
|
1013 |
+
"type": "git",
|
1014 |
+
"url": "https://github.com/symfony/debug.git",
|
1015 |
+
"reference": "af4987aa4a5630e9615be9d9c3ed1b0f24ca449c"
|
1016 |
+
},
|
1017 |
+
"dist": {
|
1018 |
+
"type": "zip",
|
1019 |
+
"url": "https://api.github.com/repos/symfony/debug/zipball/af4987aa4a5630e9615be9d9c3ed1b0f24ca449c",
|
1020 |
+
"reference": "af4987aa4a5630e9615be9d9c3ed1b0f24ca449c",
|
1021 |
+
"shasum": ""
|
1022 |
+
},
|
1023 |
+
"require": {
|
1024 |
+
"php": ">=7.1.3",
|
1025 |
+
"psr/log": "~1.0",
|
1026 |
+
"symfony/polyfill-php80": "^1.15"
|
1027 |
+
},
|
1028 |
+
"conflict": {
|
1029 |
+
"symfony/http-kernel": "<3.4"
|
1030 |
+
},
|
1031 |
+
"require-dev": {
|
1032 |
+
"symfony/http-kernel": "^3.4|^4.0|^5.0"
|
1033 |
+
},
|
1034 |
+
"type": "library",
|
1035 |
+
"autoload": {
|
1036 |
+
"psr-4": {
|
1037 |
+
"Symfony\\Component\\Debug\\": ""
|
1038 |
+
},
|
1039 |
+
"exclude-from-classmap": [
|
1040 |
+
"/Tests/"
|
1041 |
+
]
|
1042 |
+
},
|
1043 |
+
"notification-url": "https://packagist.org/downloads/",
|
1044 |
+
"license": [
|
1045 |
+
"MIT"
|
1046 |
+
],
|
1047 |
+
"authors": [
|
1048 |
+
{
|
1049 |
+
"name": "Fabien Potencier",
|
1050 |
+
"email": "fabien@symfony.com"
|
1051 |
+
},
|
1052 |
+
{
|
1053 |
+
"name": "Symfony Community",
|
1054 |
+
"homepage": "https://symfony.com/contributors"
|
1055 |
+
}
|
1056 |
+
],
|
1057 |
+
"description": "Provides tools to ease debugging PHP code",
|
1058 |
+
"homepage": "https://symfony.com",
|
1059 |
+
"time": "2021-01-27T09:09:26+00:00"
|
1060 |
+
},
|
1061 |
+
{
|
1062 |
+
"name": "symfony/deprecation-contracts",
|
1063 |
+
"version": "v2.2.0",
|
1064 |
+
"source": {
|
1065 |
+
"type": "git",
|
1066 |
+
"url": "https://github.com/symfony/deprecation-contracts.git",
|
1067 |
+
"reference": "5fa56b4074d1ae755beb55617ddafe6f5d78f665"
|
1068 |
+
},
|
1069 |
+
"dist": {
|
1070 |
+
"type": "zip",
|
1071 |
+
"url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/5fa56b4074d1ae755beb55617ddafe6f5d78f665",
|
1072 |
+
"reference": "5fa56b4074d1ae755beb55617ddafe6f5d78f665",
|
1073 |
+
"shasum": ""
|
1074 |
+
},
|
1075 |
+
"require": {
|
1076 |
+
"php": ">=7.1"
|
1077 |
+
},
|
1078 |
+
"type": "library",
|
1079 |
+
"extra": {
|
1080 |
+
"branch-alias": {
|
1081 |
+
"dev-master": "2.2-dev"
|
1082 |
+
},
|
1083 |
+
"thanks": {
|
1084 |
+
"name": "symfony/contracts",
|
1085 |
+
"url": "https://github.com/symfony/contracts"
|
1086 |
+
}
|
1087 |
+
},
|
1088 |
+
"autoload": {
|
1089 |
+
"files": [
|
1090 |
+
"function.php"
|
1091 |
+
]
|
1092 |
+
},
|
1093 |
+
"notification-url": "https://packagist.org/downloads/",
|
1094 |
+
"license": [
|
1095 |
+
"MIT"
|
1096 |
+
],
|
1097 |
+
"authors": [
|
1098 |
+
{
|
1099 |
+
"name": "Nicolas Grekas",
|
1100 |
+
"email": "p@tchwork.com"
|
1101 |
+
},
|
1102 |
+
{
|
1103 |
+
"name": "Symfony Community",
|
1104 |
+
"homepage": "https://symfony.com/contributors"
|
1105 |
+
}
|
1106 |
+
],
|
1107 |
+
"description": "A generic function and convention to trigger deprecation notices",
|
1108 |
+
"homepage": "https://symfony.com",
|
1109 |
+
"time": "2020-09-07T11:33:47+00:00"
|
1110 |
+
},
|
1111 |
+
{
|
1112 |
+
"name": "symfony/event-dispatcher",
|
1113 |
+
"version": "v5.2.3",
|
1114 |
+
"source": {
|
1115 |
+
"type": "git",
|
1116 |
+
"url": "https://github.com/symfony/event-dispatcher.git",
|
1117 |
+
"reference": "4f9760f8074978ad82e2ce854dff79a71fe45367"
|
1118 |
+
},
|
1119 |
+
"dist": {
|
1120 |
+
"type": "zip",
|
1121 |
+
"url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/4f9760f8074978ad82e2ce854dff79a71fe45367",
|
1122 |
+
"reference": "4f9760f8074978ad82e2ce854dff79a71fe45367",
|
1123 |
+
"shasum": ""
|
1124 |
+
},
|
1125 |
+
"require": {
|
1126 |
+
"php": ">=7.2.5",
|
1127 |
+
"symfony/deprecation-contracts": "^2.1",
|
1128 |
+
"symfony/event-dispatcher-contracts": "^2",
|
1129 |
+
"symfony/polyfill-php80": "^1.15"
|
1130 |
+
},
|
1131 |
+
"conflict": {
|
1132 |
+
"symfony/dependency-injection": "<4.4"
|
1133 |
+
},
|
1134 |
+
"provide": {
|
1135 |
+
"psr/event-dispatcher-implementation": "1.0",
|
1136 |
+
"symfony/event-dispatcher-implementation": "2.0"
|
1137 |
+
},
|
1138 |
+
"require-dev": {
|
1139 |
+
"psr/log": "~1.0",
|
1140 |
+
"symfony/config": "^4.4|^5.0",
|
1141 |
+
"symfony/dependency-injection": "^4.4|^5.0",
|
1142 |
+
"symfony/error-handler": "^4.4|^5.0",
|
1143 |
+
"symfony/expression-language": "^4.4|^5.0",
|
1144 |
+
"symfony/http-foundation": "^4.4|^5.0",
|
1145 |
+
"symfony/service-contracts": "^1.1|^2",
|
1146 |
+
"symfony/stopwatch": "^4.4|^5.0"
|
1147 |
+
},
|
1148 |
+
"suggest": {
|
1149 |
+
"symfony/dependency-injection": "",
|
1150 |
+
"symfony/http-kernel": ""
|
1151 |
+
},
|
1152 |
+
"type": "library",
|
1153 |
+
"autoload": {
|
1154 |
+
"psr-4": {
|
1155 |
+
"Symfony\\Component\\EventDispatcher\\": ""
|
1156 |
+
},
|
1157 |
+
"exclude-from-classmap": [
|
1158 |
+
"/Tests/"
|
1159 |
+
]
|
1160 |
+
},
|
1161 |
+
"notification-url": "https://packagist.org/downloads/",
|
1162 |
+
"license": [
|
1163 |
+
"MIT"
|
1164 |
+
],
|
1165 |
+
"authors": [
|
1166 |
+
{
|
1167 |
+
"name": "Fabien Potencier",
|
1168 |
+
"email": "fabien@symfony.com"
|
1169 |
+
},
|
1170 |
+
{
|
1171 |
+
"name": "Symfony Community",
|
1172 |
+
"homepage": "https://symfony.com/contributors"
|
1173 |
+
}
|
1174 |
+
],
|
1175 |
+
"description": "Provides tools that allow your application components to communicate with each other by dispatching events and listening to them",
|
1176 |
+
"homepage": "https://symfony.com",
|
1177 |
+
"time": "2021-01-27T10:36:42+00:00"
|
1178 |
+
},
|
1179 |
+
{
|
1180 |
+
"name": "symfony/event-dispatcher-contracts",
|
1181 |
+
"version": "v2.2.0",
|
1182 |
+
"source": {
|
1183 |
+
"type": "git",
|
1184 |
+
"url": "https://github.com/symfony/event-dispatcher-contracts.git",
|
1185 |
+
"reference": "0ba7d54483095a198fa51781bc608d17e84dffa2"
|
1186 |
+
},
|
1187 |
+
"dist": {
|
1188 |
+
"type": "zip",
|
1189 |
+
"url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/0ba7d54483095a198fa51781bc608d17e84dffa2",
|
1190 |
+
"reference": "0ba7d54483095a198fa51781bc608d17e84dffa2",
|
1191 |
+
"shasum": ""
|
1192 |
+
},
|
1193 |
+
"require": {
|
1194 |
+
"php": ">=7.2.5",
|
1195 |
+
"psr/event-dispatcher": "^1"
|
1196 |
+
},
|
1197 |
+
"suggest": {
|
1198 |
+
"symfony/event-dispatcher-implementation": ""
|
1199 |
+
},
|
1200 |
+
"type": "library",
|
1201 |
+
"extra": {
|
1202 |
+
"branch-alias": {
|
1203 |
+
"dev-master": "2.2-dev"
|
1204 |
+
},
|
1205 |
+
"thanks": {
|
1206 |
+
"name": "symfony/contracts",
|
1207 |
+
"url": "https://github.com/symfony/contracts"
|
1208 |
+
}
|
1209 |
+
},
|
1210 |
+
"autoload": {
|
1211 |
+
"psr-4": {
|
1212 |
+
"Symfony\\Contracts\\EventDispatcher\\": ""
|
1213 |
+
}
|
1214 |
+
},
|
1215 |
+
"notification-url": "https://packagist.org/downloads/",
|
1216 |
+
"license": [
|
1217 |
+
"MIT"
|
1218 |
+
],
|
1219 |
+
"authors": [
|
1220 |
+
{
|
1221 |
+
"name": "Nicolas Grekas",
|
1222 |
+
"email": "p@tchwork.com"
|
1223 |
+
},
|
1224 |
+
{
|
1225 |
+
"name": "Symfony Community",
|
1226 |
+
"homepage": "https://symfony.com/contributors"
|
1227 |
+
}
|
1228 |
+
],
|
1229 |
+
"description": "Generic abstractions related to dispatching event",
|
1230 |
+
"homepage": "https://symfony.com",
|
1231 |
+
"keywords": [
|
1232 |
+
"abstractions",
|
1233 |
+
"contracts",
|
1234 |
+
"decoupling",
|
1235 |
+
"interfaces",
|
1236 |
+
"interoperability",
|
1237 |
+
"standards"
|
1238 |
+
],
|
1239 |
+
"time": "2020-09-07T11:33:47+00:00"
|
1240 |
+
},
|
1241 |
+
{
|
1242 |
+
"name": "symfony/filesystem",
|
1243 |
+
"version": "v3.4.47",
|
1244 |
+
"source": {
|
1245 |
+
"type": "git",
|
1246 |
+
"url": "https://github.com/symfony/filesystem.git",
|
1247 |
+
"reference": "e58d7841cddfed6e846829040dca2cca0ebbbbb3"
|
1248 |
+
},
|
1249 |
+
"dist": {
|
1250 |
+
"type": "zip",
|
1251 |
+
"url": "https://api.github.com/repos/symfony/filesystem/zipball/e58d7841cddfed6e846829040dca2cca0ebbbbb3",
|
1252 |
+
"reference": "e58d7841cddfed6e846829040dca2cca0ebbbbb3",
|
1253 |
+
"shasum": ""
|
1254 |
+
},
|
1255 |
+
"require": {
|
1256 |
+
"php": "^5.5.9|>=7.0.8",
|
1257 |
+
"symfony/polyfill-ctype": "~1.8"
|
1258 |
+
},
|
1259 |
+
"type": "library",
|
1260 |
+
"autoload": {
|
1261 |
+
"psr-4": {
|
1262 |
+
"Symfony\\Component\\Filesystem\\": ""
|
1263 |
+
},
|
1264 |
+
"exclude-from-classmap": [
|
1265 |
+
"/Tests/"
|
1266 |
+
]
|
1267 |
+
},
|
1268 |
+
"notification-url": "https://packagist.org/downloads/",
|
1269 |
+
"license": [
|
1270 |
+
"MIT"
|
1271 |
+
],
|
1272 |
+
"authors": [
|
1273 |
+
{
|
1274 |
+
"name": "Fabien Potencier",
|
1275 |
+
"email": "fabien@symfony.com"
|
1276 |
+
},
|
1277 |
+
{
|
1278 |
+
"name": "Symfony Community",
|
1279 |
+
"homepage": "https://symfony.com/contributors"
|
1280 |
+
}
|
1281 |
+
],
|
1282 |
+
"description": "Symfony Filesystem Component",
|
1283 |
+
"homepage": "https://symfony.com",
|
1284 |
+
"time": "2020-10-24T10:57:07+00:00"
|
1285 |
+
},
|
1286 |
+
{
|
1287 |
+
"name": "symfony/finder",
|
1288 |
+
"version": "v5.2.3",
|
1289 |
+
"source": {
|
1290 |
+
"type": "git",
|
1291 |
+
"url": "https://github.com/symfony/finder.git",
|
1292 |
+
"reference": "4adc8d172d602008c204c2e16956f99257248e03"
|
1293 |
+
},
|
1294 |
+
"dist": {
|
1295 |
+
"type": "zip",
|
1296 |
+
"url": "https://api.github.com/repos/symfony/finder/zipball/4adc8d172d602008c204c2e16956f99257248e03",
|
1297 |
+
"reference": "4adc8d172d602008c204c2e16956f99257248e03",
|
1298 |
+
"shasum": ""
|
1299 |
+
},
|
1300 |
+
"require": {
|
1301 |
+
"php": ">=7.2.5"
|
1302 |
+
},
|
1303 |
+
"type": "library",
|
1304 |
+
"autoload": {
|
1305 |
+
"psr-4": {
|
1306 |
+
"Symfony\\Component\\Finder\\": ""
|
1307 |
+
},
|
1308 |
+
"exclude-from-classmap": [
|
1309 |
+
"/Tests/"
|
1310 |
+
]
|
1311 |
+
},
|
1312 |
+
"notification-url": "https://packagist.org/downloads/",
|
1313 |
+
"license": [
|
1314 |
+
"MIT"
|
1315 |
+
],
|
1316 |
+
"authors": [
|
1317 |
+
{
|
1318 |
+
"name": "Fabien Potencier",
|
1319 |
+
"email": "fabien@symfony.com"
|
1320 |
+
},
|
1321 |
+
{
|
1322 |
+
"name": "Symfony Community",
|
1323 |
+
"homepage": "https://symfony.com/contributors"
|
1324 |
+
}
|
1325 |
+
],
|
1326 |
+
"description": "Finds files and directories via an intuitive fluent interface",
|
1327 |
+
"homepage": "https://symfony.com",
|
1328 |
+
"time": "2021-01-28T22:06:19+00:00"
|
1329 |
+
},
|
1330 |
+
{
|
1331 |
+
"name": "symfony/options-resolver",
|
1332 |
+
"version": "v5.2.3",
|
1333 |
+
"source": {
|
1334 |
+
"type": "git",
|
1335 |
+
"url": "https://github.com/symfony/options-resolver.git",
|
1336 |
+
"reference": "5d0f633f9bbfcf7ec642a2b5037268e61b0a62ce"
|
1337 |
+
},
|
1338 |
+
"dist": {
|
1339 |
+
"type": "zip",
|
1340 |
+
"url": "https://api.github.com/repos/symfony/options-resolver/zipball/5d0f633f9bbfcf7ec642a2b5037268e61b0a62ce",
|
1341 |
+
"reference": "5d0f633f9bbfcf7ec642a2b5037268e61b0a62ce",
|
1342 |
+
"shasum": ""
|
1343 |
+
},
|
1344 |
+
"require": {
|
1345 |
+
"php": ">=7.2.5",
|
1346 |
+
"symfony/deprecation-contracts": "^2.1",
|
1347 |
+
"symfony/polyfill-php73": "~1.0",
|
1348 |
+
"symfony/polyfill-php80": "^1.15"
|
1349 |
+
},
|
1350 |
+
"type": "library",
|
1351 |
+
"autoload": {
|
1352 |
+
"psr-4": {
|
1353 |
+
"Symfony\\Component\\OptionsResolver\\": ""
|
1354 |
+
},
|
1355 |
+
"exclude-from-classmap": [
|
1356 |
+
"/Tests/"
|
1357 |
+
]
|
1358 |
+
},
|
1359 |
+
"notification-url": "https://packagist.org/downloads/",
|
1360 |
+
"license": [
|
1361 |
+
"MIT"
|
1362 |
+
],
|
1363 |
+
"authors": [
|
1364 |
+
{
|
1365 |
+
"name": "Fabien Potencier",
|
1366 |
+
"email": "fabien@symfony.com"
|
1367 |
+
},
|
1368 |
+
{
|
1369 |
+
"name": "Symfony Community",
|
1370 |
+
"homepage": "https://symfony.com/contributors"
|
1371 |
+
}
|
1372 |
+
],
|
1373 |
+
"description": "Provides an improved replacement for the array_replace PHP function",
|
1374 |
+
"homepage": "https://symfony.com",
|
1375 |
+
"keywords": [
|
1376 |
+
"config",
|
1377 |
+
"configuration",
|
1378 |
+
"options"
|
1379 |
+
],
|
1380 |
+
"time": "2021-01-27T12:56:27+00:00"
|
1381 |
+
},
|
1382 |
+
{
|
1383 |
+
"name": "symfony/polyfill-ctype",
|
1384 |
+
"version": "v1.22.1",
|
1385 |
+
"source": {
|
1386 |
+
"type": "git",
|
1387 |
+
"url": "https://github.com/symfony/polyfill-ctype.git",
|
1388 |
+
"reference": "c6c942b1ac76c82448322025e084cadc56048b4e"
|
1389 |
+
},
|
1390 |
+
"dist": {
|
1391 |
+
"type": "zip",
|
1392 |
+
"url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/c6c942b1ac76c82448322025e084cadc56048b4e",
|
1393 |
+
"reference": "c6c942b1ac76c82448322025e084cadc56048b4e",
|
1394 |
+
"shasum": ""
|
1395 |
+
},
|
1396 |
+
"require": {
|
1397 |
+
"php": ">=7.1"
|
1398 |
+
},
|
1399 |
+
"suggest": {
|
1400 |
+
"ext-ctype": "For best performance"
|
1401 |
+
},
|
1402 |
+
"type": "library",
|
1403 |
+
"extra": {
|
1404 |
+
"branch-alias": {
|
1405 |
+
"dev-main": "1.22-dev"
|
1406 |
+
},
|
1407 |
+
"thanks": {
|
1408 |
+
"name": "symfony/polyfill",
|
1409 |
+
"url": "https://github.com/symfony/polyfill"
|
1410 |
+
}
|
1411 |
+
},
|
1412 |
+
"autoload": {
|
1413 |
+
"psr-4": {
|
1414 |
+
"Symfony\\Polyfill\\Ctype\\": ""
|
1415 |
+
},
|
1416 |
+
"files": [
|
1417 |
+
"bootstrap.php"
|
1418 |
+
]
|
1419 |
+
},
|
1420 |
+
"notification-url": "https://packagist.org/downloads/",
|
1421 |
+
"license": [
|
1422 |
+
"MIT"
|
1423 |
+
],
|
1424 |
+
"authors": [
|
1425 |
+
{
|
1426 |
+
"name": "Gert de Pagter",
|
1427 |
+
"email": "BackEndTea@gmail.com"
|
1428 |
+
},
|
1429 |
+
{
|
1430 |
+
"name": "Symfony Community",
|
1431 |
+
"homepage": "https://symfony.com/contributors"
|
1432 |
+
}
|
1433 |
+
],
|
1434 |
+
"description": "Symfony polyfill for ctype functions",
|
1435 |
+
"homepage": "https://symfony.com",
|
1436 |
+
"keywords": [
|
1437 |
+
"compatibility",
|
1438 |
+
"ctype",
|
1439 |
+
"polyfill",
|
1440 |
+
"portable"
|
1441 |
+
],
|
1442 |
+
"time": "2021-01-07T16:49:33+00:00"
|
1443 |
+
},
|
1444 |
+
{
|
1445 |
+
"name": "symfony/polyfill-mbstring",
|
1446 |
+
"version": "v1.22.1",
|
1447 |
+
"source": {
|
1448 |
+
"type": "git",
|
1449 |
+
"url": "https://github.com/symfony/polyfill-mbstring.git",
|
1450 |
+
"reference": "5232de97ee3b75b0360528dae24e73db49566ab1"
|
1451 |
+
},
|
1452 |
+
"dist": {
|
1453 |
+
"type": "zip",
|
1454 |
+
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/5232de97ee3b75b0360528dae24e73db49566ab1",
|
1455 |
+
"reference": "5232de97ee3b75b0360528dae24e73db49566ab1",
|
1456 |
+
"shasum": ""
|
1457 |
+
},
|
1458 |
+
"require": {
|
1459 |
+
"php": ">=7.1"
|
1460 |
+
},
|
1461 |
+
"suggest": {
|
1462 |
+
"ext-mbstring": "For best performance"
|
1463 |
+
},
|
1464 |
+
"type": "library",
|
1465 |
+
"extra": {
|
1466 |
+
"branch-alias": {
|
1467 |
+
"dev-main": "1.22-dev"
|
1468 |
+
},
|
1469 |
+
"thanks": {
|
1470 |
+
"name": "symfony/polyfill",
|
1471 |
+
"url": "https://github.com/symfony/polyfill"
|
1472 |
+
}
|
1473 |
+
},
|
1474 |
+
"autoload": {
|
1475 |
+
"psr-4": {
|
1476 |
+
"Symfony\\Polyfill\\Mbstring\\": ""
|
1477 |
+
},
|
1478 |
+
"files": [
|
1479 |
+
"bootstrap.php"
|
1480 |
+
]
|
1481 |
+
},
|
1482 |
+
"notification-url": "https://packagist.org/downloads/",
|
1483 |
+
"license": [
|
1484 |
+
"MIT"
|
1485 |
+
],
|
1486 |
+
"authors": [
|
1487 |
+
{
|
1488 |
+
"name": "Nicolas Grekas",
|
1489 |
+
"email": "p@tchwork.com"
|
1490 |
+
},
|
1491 |
+
{
|
1492 |
+
"name": "Symfony Community",
|
1493 |
+
"homepage": "https://symfony.com/contributors"
|
1494 |
+
}
|
1495 |
+
],
|
1496 |
+
"description": "Symfony polyfill for the Mbstring extension",
|
1497 |
+
"homepage": "https://symfony.com",
|
1498 |
+
"keywords": [
|
1499 |
+
"compatibility",
|
1500 |
+
"mbstring",
|
1501 |
+
"polyfill",
|
1502 |
+
"portable",
|
1503 |
+
"shim"
|
1504 |
+
],
|
1505 |
+
"time": "2021-01-22T09:19:47+00:00"
|
1506 |
+
},
|
1507 |
+
{
|
1508 |
+
"name": "symfony/polyfill-php70",
|
1509 |
+
"version": "v1.20.0",
|
1510 |
+
"source": {
|
1511 |
+
"type": "git",
|
1512 |
+
"url": "https://github.com/symfony/polyfill-php70.git",
|
1513 |
+
"reference": "5f03a781d984aae42cebd18e7912fa80f02ee644"
|
1514 |
+
},
|
1515 |
+
"dist": {
|
1516 |
+
"type": "zip",
|
1517 |
+
"url": "https://api.github.com/repos/symfony/polyfill-php70/zipball/5f03a781d984aae42cebd18e7912fa80f02ee644",
|
1518 |
+
"reference": "5f03a781d984aae42cebd18e7912fa80f02ee644",
|
1519 |
+
"shasum": ""
|
1520 |
+
},
|
1521 |
+
"require": {
|
1522 |
+
"php": ">=7.1"
|
1523 |
+
},
|
1524 |
+
"type": "metapackage",
|
1525 |
+
"extra": {
|
1526 |
+
"branch-alias": {
|
1527 |
+
"dev-main": "1.20-dev"
|
1528 |
+
},
|
1529 |
+
"thanks": {
|
1530 |
+
"name": "symfony/polyfill",
|
1531 |
+
"url": "https://github.com/symfony/polyfill"
|
1532 |
+
}
|
1533 |
+
},
|
1534 |
+
"notification-url": "https://packagist.org/downloads/",
|
1535 |
+
"license": [
|
1536 |
+
"MIT"
|
1537 |
+
],
|
1538 |
+
"authors": [
|
1539 |
+
{
|
1540 |
+
"name": "Nicolas Grekas",
|
1541 |
+
"email": "p@tchwork.com"
|
1542 |
+
},
|
1543 |
+
{
|
1544 |
+
"name": "Symfony Community",
|
1545 |
+
"homepage": "https://symfony.com/contributors"
|
1546 |
+
}
|
1547 |
+
],
|
1548 |
+
"description": "Symfony polyfill backporting some PHP 7.0+ features to lower PHP versions",
|
1549 |
+
"homepage": "https://symfony.com",
|
1550 |
+
"keywords": [
|
1551 |
+
"compatibility",
|
1552 |
+
"polyfill",
|
1553 |
+
"portable",
|
1554 |
+
"shim"
|
1555 |
+
],
|
1556 |
+
"time": "2020-10-23T14:02:19+00:00"
|
1557 |
+
},
|
1558 |
+
{
|
1559 |
+
"name": "symfony/polyfill-php72",
|
1560 |
+
"version": "v1.22.1",
|
1561 |
+
"source": {
|
1562 |
+
"type": "git",
|
1563 |
+
"url": "https://github.com/symfony/polyfill-php72.git",
|
1564 |
+
"reference": "cc6e6f9b39fe8075b3dabfbaf5b5f645ae1340c9"
|
1565 |
+
},
|
1566 |
+
"dist": {
|
1567 |
+
"type": "zip",
|
1568 |
+
"url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/cc6e6f9b39fe8075b3dabfbaf5b5f645ae1340c9",
|
1569 |
+
"reference": "cc6e6f9b39fe8075b3dabfbaf5b5f645ae1340c9",
|
1570 |
+
"shasum": ""
|
1571 |
+
},
|
1572 |
+
"require": {
|
1573 |
+
"php": ">=7.1"
|
1574 |
+
},
|
1575 |
+
"type": "library",
|
1576 |
+
"extra": {
|
1577 |
+
"branch-alias": {
|
1578 |
+
"dev-main": "1.22-dev"
|
1579 |
+
},
|
1580 |
+
"thanks": {
|
1581 |
+
"name": "symfony/polyfill",
|
1582 |
+
"url": "https://github.com/symfony/polyfill"
|
1583 |
+
}
|
1584 |
+
},
|
1585 |
+
"autoload": {
|
1586 |
+
"psr-4": {
|
1587 |
+
"Symfony\\Polyfill\\Php72\\": ""
|
1588 |
+
},
|
1589 |
+
"files": [
|
1590 |
+
"bootstrap.php"
|
1591 |
+
]
|
1592 |
+
},
|
1593 |
+
"notification-url": "https://packagist.org/downloads/",
|
1594 |
+
"license": [
|
1595 |
+
"MIT"
|
1596 |
+
],
|
1597 |
+
"authors": [
|
1598 |
+
{
|
1599 |
+
"name": "Nicolas Grekas",
|
1600 |
+
"email": "p@tchwork.com"
|
1601 |
+
},
|
1602 |
+
{
|
1603 |
+
"name": "Symfony Community",
|
1604 |
+
"homepage": "https://symfony.com/contributors"
|
1605 |
+
}
|
1606 |
+
],
|
1607 |
+
"description": "Symfony polyfill backporting some PHP 7.2+ features to lower PHP versions",
|
1608 |
+
"homepage": "https://symfony.com",
|
1609 |
+
"keywords": [
|
1610 |
+
"compatibility",
|
1611 |
+
"polyfill",
|
1612 |
+
"portable",
|
1613 |
+
"shim"
|
1614 |
+
],
|
1615 |
+
"time": "2021-01-07T16:49:33+00:00"
|
1616 |
+
},
|
1617 |
+
{
|
1618 |
+
"name": "symfony/polyfill-php73",
|
1619 |
+
"version": "v1.22.1",
|
1620 |
+
"source": {
|
1621 |
+
"type": "git",
|
1622 |
+
"url": "https://github.com/symfony/polyfill-php73.git",
|
1623 |
+
"reference": "a678b42e92f86eca04b7fa4c0f6f19d097fb69e2"
|
1624 |
+
},
|
1625 |
+
"dist": {
|
1626 |
+
"type": "zip",
|
1627 |
+
"url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/a678b42e92f86eca04b7fa4c0f6f19d097fb69e2",
|
1628 |
+
"reference": "a678b42e92f86eca04b7fa4c0f6f19d097fb69e2",
|
1629 |
+
"shasum": ""
|
1630 |
+
},
|
1631 |
+
"require": {
|
1632 |
+
"php": ">=7.1"
|
1633 |
+
},
|
1634 |
+
"type": "library",
|
1635 |
+
"extra": {
|
1636 |
+
"branch-alias": {
|
1637 |
+
"dev-main": "1.22-dev"
|
1638 |
+
},
|
1639 |
+
"thanks": {
|
1640 |
+
"name": "symfony/polyfill",
|
1641 |
+
"url": "https://github.com/symfony/polyfill"
|
1642 |
+
}
|
1643 |
+
},
|
1644 |
+
"autoload": {
|
1645 |
+
"psr-4": {
|
1646 |
+
"Symfony\\Polyfill\\Php73\\": ""
|
1647 |
+
},
|
1648 |
+
"files": [
|
1649 |
+
"bootstrap.php"
|
1650 |
+
],
|
1651 |
+
"classmap": [
|
1652 |
+
"Resources/stubs"
|
1653 |
+
]
|
1654 |
+
},
|
1655 |
+
"notification-url": "https://packagist.org/downloads/",
|
1656 |
+
"license": [
|
1657 |
+
"MIT"
|
1658 |
+
],
|
1659 |
+
"authors": [
|
1660 |
+
{
|
1661 |
+
"name": "Nicolas Grekas",
|
1662 |
+
"email": "p@tchwork.com"
|
1663 |
+
},
|
1664 |
+
{
|
1665 |
+
"name": "Symfony Community",
|
1666 |
+
"homepage": "https://symfony.com/contributors"
|
1667 |
+
}
|
1668 |
+
],
|
1669 |
+
"description": "Symfony polyfill backporting some PHP 7.3+ features to lower PHP versions",
|
1670 |
+
"homepage": "https://symfony.com",
|
1671 |
+
"keywords": [
|
1672 |
+
"compatibility",
|
1673 |
+
"polyfill",
|
1674 |
+
"portable",
|
1675 |
+
"shim"
|
1676 |
+
],
|
1677 |
+
"time": "2021-01-07T16:49:33+00:00"
|
1678 |
+
},
|
1679 |
+
{
|
1680 |
+
"name": "symfony/polyfill-php80",
|
1681 |
+
"version": "v1.22.1",
|
1682 |
+
"source": {
|
1683 |
+
"type": "git",
|
1684 |
+
"url": "https://github.com/symfony/polyfill-php80.git",
|
1685 |
+
"reference": "dc3063ba22c2a1fd2f45ed856374d79114998f91"
|
1686 |
+
},
|
1687 |
+
"dist": {
|
1688 |
+
"type": "zip",
|
1689 |
+
"url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/dc3063ba22c2a1fd2f45ed856374d79114998f91",
|
1690 |
+
"reference": "dc3063ba22c2a1fd2f45ed856374d79114998f91",
|
1691 |
+
"shasum": ""
|
1692 |
+
},
|
1693 |
+
"require": {
|
1694 |
+
"php": ">=7.1"
|
1695 |
+
},
|
1696 |
+
"type": "library",
|
1697 |
+
"extra": {
|
1698 |
+
"branch-alias": {
|
1699 |
+
"dev-main": "1.22-dev"
|
1700 |
+
},
|
1701 |
+
"thanks": {
|
1702 |
+
"name": "symfony/polyfill",
|
1703 |
+
"url": "https://github.com/symfony/polyfill"
|
1704 |
+
}
|
1705 |
+
},
|
1706 |
+
"autoload": {
|
1707 |
+
"psr-4": {
|
1708 |
+
"Symfony\\Polyfill\\Php80\\": ""
|
1709 |
+
},
|
1710 |
+
"files": [
|
1711 |
+
"bootstrap.php"
|
1712 |
+
],
|
1713 |
+
"classmap": [
|
1714 |
+
"Resources/stubs"
|
1715 |
+
]
|
1716 |
+
},
|
1717 |
+
"notification-url": "https://packagist.org/downloads/",
|
1718 |
+
"license": [
|
1719 |
+
"MIT"
|
1720 |
+
],
|
1721 |
+
"authors": [
|
1722 |
+
{
|
1723 |
+
"name": "Ion Bazan",
|
1724 |
+
"email": "ion.bazan@gmail.com"
|
1725 |
+
},
|
1726 |
+
{
|
1727 |
+
"name": "Nicolas Grekas",
|
1728 |
+
"email": "p@tchwork.com"
|
1729 |
+
},
|
1730 |
+
{
|
1731 |
+
"name": "Symfony Community",
|
1732 |
+
"homepage": "https://symfony.com/contributors"
|
1733 |
+
}
|
1734 |
+
],
|
1735 |
+
"description": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions",
|
1736 |
+
"homepage": "https://symfony.com",
|
1737 |
+
"keywords": [
|
1738 |
+
"compatibility",
|
1739 |
+
"polyfill",
|
1740 |
+
"portable",
|
1741 |
+
"shim"
|
1742 |
+
],
|
1743 |
+
"time": "2021-01-07T16:49:33+00:00"
|
1744 |
+
},
|
1745 |
+
{
|
1746 |
+
"name": "symfony/process",
|
1747 |
+
"version": "v5.2.3",
|
1748 |
+
"source": {
|
1749 |
+
"type": "git",
|
1750 |
+
"url": "https://github.com/symfony/process.git",
|
1751 |
+
"reference": "313a38f09c77fbcdc1d223e57d368cea76a2fd2f"
|
1752 |
+
},
|
1753 |
+
"dist": {
|
1754 |
+
"type": "zip",
|
1755 |
+
"url": "https://api.github.com/repos/symfony/process/zipball/313a38f09c77fbcdc1d223e57d368cea76a2fd2f",
|
1756 |
+
"reference": "313a38f09c77fbcdc1d223e57d368cea76a2fd2f",
|
1757 |
+
"shasum": ""
|
1758 |
+
},
|
1759 |
+
"require": {
|
1760 |
+
"php": ">=7.2.5",
|
1761 |
+
"symfony/polyfill-php80": "^1.15"
|
1762 |
+
},
|
1763 |
+
"type": "library",
|
1764 |
+
"autoload": {
|
1765 |
+
"psr-4": {
|
1766 |
+
"Symfony\\Component\\Process\\": ""
|
1767 |
+
},
|
1768 |
+
"exclude-from-classmap": [
|
1769 |
+
"/Tests/"
|
1770 |
+
]
|
1771 |
+
},
|
1772 |
+
"notification-url": "https://packagist.org/downloads/",
|
1773 |
+
"license": [
|
1774 |
+
"MIT"
|
1775 |
+
],
|
1776 |
+
"authors": [
|
1777 |
+
{
|
1778 |
+
"name": "Fabien Potencier",
|
1779 |
+
"email": "fabien@symfony.com"
|
1780 |
+
},
|
1781 |
+
{
|
1782 |
+
"name": "Symfony Community",
|
1783 |
+
"homepage": "https://symfony.com/contributors"
|
1784 |
+
}
|
1785 |
+
],
|
1786 |
+
"description": "Executes commands in sub-processes",
|
1787 |
+
"homepage": "https://symfony.com",
|
1788 |
+
"time": "2021-01-27T10:15:41+00:00"
|
1789 |
+
},
|
1790 |
+
{
|
1791 |
+
"name": "symfony/service-contracts",
|
1792 |
+
"version": "v2.2.0",
|
1793 |
+
"source": {
|
1794 |
+
"type": "git",
|
1795 |
+
"url": "https://github.com/symfony/service-contracts.git",
|
1796 |
+
"reference": "d15da7ba4957ffb8f1747218be9e1a121fd298a1"
|
1797 |
+
},
|
1798 |
+
"dist": {
|
1799 |
+
"type": "zip",
|
1800 |
+
"url": "https://api.github.com/repos/symfony/service-contracts/zipball/d15da7ba4957ffb8f1747218be9e1a121fd298a1",
|
1801 |
+
"reference": "d15da7ba4957ffb8f1747218be9e1a121fd298a1",
|
1802 |
+
"shasum": ""
|
1803 |
+
},
|
1804 |
+
"require": {
|
1805 |
+
"php": ">=7.2.5",
|
1806 |
+
"psr/container": "^1.0"
|
1807 |
+
},
|
1808 |
+
"suggest": {
|
1809 |
+
"symfony/service-implementation": ""
|
1810 |
+
},
|
1811 |
+
"type": "library",
|
1812 |
+
"extra": {
|
1813 |
+
"branch-alias": {
|
1814 |
+
"dev-master": "2.2-dev"
|
1815 |
+
},
|
1816 |
+
"thanks": {
|
1817 |
+
"name": "symfony/contracts",
|
1818 |
+
"url": "https://github.com/symfony/contracts"
|
1819 |
+
}
|
1820 |
+
},
|
1821 |
+
"autoload": {
|
1822 |
+
"psr-4": {
|
1823 |
+
"Symfony\\Contracts\\Service\\": ""
|
1824 |
+
}
|
1825 |
+
},
|
1826 |
+
"notification-url": "https://packagist.org/downloads/",
|
1827 |
+
"license": [
|
1828 |
+
"MIT"
|
1829 |
+
],
|
1830 |
+
"authors": [
|
1831 |
+
{
|
1832 |
+
"name": "Nicolas Grekas",
|
1833 |
+
"email": "p@tchwork.com"
|
1834 |
+
},
|
1835 |
+
{
|
1836 |
+
"name": "Symfony Community",
|
1837 |
+
"homepage": "https://symfony.com/contributors"
|
1838 |
+
}
|
1839 |
+
],
|
1840 |
+
"description": "Generic abstractions related to writing services",
|
1841 |
+
"homepage": "https://symfony.com",
|
1842 |
+
"keywords": [
|
1843 |
+
"abstractions",
|
1844 |
+
"contracts",
|
1845 |
+
"decoupling",
|
1846 |
+
"interfaces",
|
1847 |
+
"interoperability",
|
1848 |
+
"standards"
|
1849 |
+
],
|
1850 |
+
"time": "2020-09-07T11:33:47+00:00"
|
1851 |
+
},
|
1852 |
+
{
|
1853 |
+
"name": "symfony/stopwatch",
|
1854 |
+
"version": "v5.2.3",
|
1855 |
+
"source": {
|
1856 |
+
"type": "git",
|
1857 |
+
"url": "https://github.com/symfony/stopwatch.git",
|
1858 |
+
"reference": "b12274acfab9d9850c52583d136a24398cdf1a0c"
|
1859 |
+
},
|
1860 |
+
"dist": {
|
1861 |
+
"type": "zip",
|
1862 |
+
"url": "https://api.github.com/repos/symfony/stopwatch/zipball/b12274acfab9d9850c52583d136a24398cdf1a0c",
|
1863 |
+
"reference": "b12274acfab9d9850c52583d136a24398cdf1a0c",
|
1864 |
+
"shasum": ""
|
1865 |
+
},
|
1866 |
+
"require": {
|
1867 |
+
"php": ">=7.2.5",
|
1868 |
+
"symfony/service-contracts": "^1.0|^2"
|
1869 |
+
},
|
1870 |
+
"type": "library",
|
1871 |
+
"autoload": {
|
1872 |
+
"psr-4": {
|
1873 |
+
"Symfony\\Component\\Stopwatch\\": ""
|
1874 |
+
},
|
1875 |
+
"exclude-from-classmap": [
|
1876 |
+
"/Tests/"
|
1877 |
+
]
|
1878 |
+
},
|
1879 |
+
"notification-url": "https://packagist.org/downloads/",
|
1880 |
+
"license": [
|
1881 |
+
"MIT"
|
1882 |
+
],
|
1883 |
+
"authors": [
|
1884 |
+
{
|
1885 |
+
"name": "Fabien Potencier",
|
1886 |
+
"email": "fabien@symfony.com"
|
1887 |
+
},
|
1888 |
+
{
|
1889 |
+
"name": "Symfony Community",
|
1890 |
+
"homepage": "https://symfony.com/contributors"
|
1891 |
+
}
|
1892 |
+
],
|
1893 |
+
"description": "Provides a way to profile code",
|
1894 |
+
"homepage": "https://symfony.com",
|
1895 |
+
"time": "2021-01-27T10:15:41+00:00"
|
1896 |
+
},
|
1897 |
+
{
|
1898 |
+
"name": "woocommerce/woocommerce-sniffs",
|
1899 |
+
"version": "0.1.0",
|
1900 |
+
"source": {
|
1901 |
+
"type": "git",
|
1902 |
+
"url": "https://github.com/woocommerce/woocommerce-sniffs.git",
|
1903 |
+
"reference": "b72b7dd2e70aa6aed16f80cdae5b1e6cce2e4c79"
|
1904 |
+
},
|
1905 |
+
"dist": {
|
1906 |
+
"type": "zip",
|
1907 |
+
"url": "https://api.github.com/repos/woocommerce/woocommerce-sniffs/zipball/b72b7dd2e70aa6aed16f80cdae5b1e6cce2e4c79",
|
1908 |
+
"reference": "b72b7dd2e70aa6aed16f80cdae5b1e6cce2e4c79",
|
1909 |
+
"shasum": ""
|
1910 |
+
},
|
1911 |
+
"require": {
|
1912 |
+
"dealerdirect/phpcodesniffer-composer-installer": "0.7.0",
|
1913 |
+
"php": ">=7.0",
|
1914 |
+
"phpcompatibility/phpcompatibility-wp": "2.1.0",
|
1915 |
+
"wp-coding-standards/wpcs": "2.3.0"
|
1916 |
+
},
|
1917 |
+
"type": "phpcodesniffer-standard",
|
1918 |
+
"notification-url": "https://packagist.org/downloads/",
|
1919 |
+
"license": [
|
1920 |
+
"MIT"
|
1921 |
+
],
|
1922 |
+
"authors": [
|
1923 |
+
{
|
1924 |
+
"name": "Claudio Sanches",
|
1925 |
+
"email": "claudio@automattic.com"
|
1926 |
+
}
|
1927 |
+
],
|
1928 |
+
"description": "WooCommerce sniffs",
|
1929 |
+
"keywords": [
|
1930 |
+
"phpcs",
|
1931 |
+
"standards",
|
1932 |
+
"woocommerce",
|
1933 |
+
"wordpress"
|
1934 |
+
],
|
1935 |
+
"time": "2020-08-06T18:23:45+00:00"
|
1936 |
+
},
|
1937 |
+
{
|
1938 |
+
"name": "wp-coding-standards/wpcs",
|
1939 |
+
"version": "2.3.0",
|
1940 |
+
"source": {
|
1941 |
+
"type": "git",
|
1942 |
+
"url": "https://github.com/WordPress/WordPress-Coding-Standards.git",
|
1943 |
+
"reference": "7da1894633f168fe244afc6de00d141f27517b62"
|
1944 |
+
},
|
1945 |
+
"dist": {
|
1946 |
+
"type": "zip",
|
1947 |
+
"url": "https://api.github.com/repos/WordPress/WordPress-Coding-Standards/zipball/7da1894633f168fe244afc6de00d141f27517b62",
|
1948 |
+
"reference": "7da1894633f168fe244afc6de00d141f27517b62",
|
1949 |
+
"shasum": ""
|
1950 |
+
},
|
1951 |
+
"require": {
|
1952 |
+
"php": ">=5.4",
|
1953 |
+
"squizlabs/php_codesniffer": "^3.3.1"
|
1954 |
+
},
|
1955 |
+
"require-dev": {
|
1956 |
+
"dealerdirect/phpcodesniffer-composer-installer": "^0.5 || ^0.6",
|
1957 |
+
"phpcompatibility/php-compatibility": "^9.0",
|
1958 |
+
"phpcsstandards/phpcsdevtools": "^1.0",
|
1959 |
+
"phpunit/phpunit": "^4.0 || ^5.0 || ^6.0 || ^7.0"
|
1960 |
+
},
|
1961 |
+
"suggest": {
|
1962 |
+
"dealerdirect/phpcodesniffer-composer-installer": "^0.6 || This Composer plugin will sort out the PHPCS 'installed_paths' automatically."
|
1963 |
+
},
|
1964 |
+
"type": "phpcodesniffer-standard",
|
1965 |
+
"notification-url": "https://packagist.org/downloads/",
|
1966 |
+
"license": [
|
1967 |
+
"MIT"
|
1968 |
+
],
|
1969 |
+
"authors": [
|
1970 |
+
{
|
1971 |
+
"name": "Contributors",
|
1972 |
+
"homepage": "https://github.com/WordPress/WordPress-Coding-Standards/graphs/contributors"
|
1973 |
+
}
|
1974 |
+
],
|
1975 |
+
"description": "PHP_CodeSniffer rules (sniffs) to enforce WordPress coding conventions",
|
1976 |
+
"keywords": [
|
1977 |
+
"phpcs",
|
1978 |
+
"standards",
|
1979 |
+
"wordpress"
|
1980 |
+
],
|
1981 |
+
"time": "2020-05-13T23:57:56+00:00"
|
1982 |
+
}
|
1983 |
+
],
|
1984 |
+
"aliases": [],
|
1985 |
+
"minimum-stability": "stable",
|
1986 |
+
"stability-flags": [],
|
1987 |
+
"prefer-stable": false,
|
1988 |
+
"prefer-lowest": false,
|
1989 |
+
"platform": [],
|
1990 |
+
"platform-dev": []
|
1991 |
+
}
|
includes/api/class-aftership-api-authentication.php
ADDED
@@ -0,0 +1,124 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* AfterShip API Authentication Class
|
4 |
+
*
|
5 |
+
* @author AfterShip
|
6 |
+
* @category API
|
7 |
+
* @package AfterShip/API
|
8 |
+
* @since 1
|
9 |
+
*/
|
10 |
+
|
11 |
+
if ( ! defined( 'ABSPATH' ) ) {
|
12 |
+
exit; // Exit if accessed directly
|
13 |
+
}
|
14 |
+
|
15 |
+
|
16 |
+
if ( ! function_exists( 'getallheaders' ) ) {
|
17 |
+
function getallheaders() {
|
18 |
+
$headers = '';
|
19 |
+
foreach ( $_SERVER as $name => $value ) {
|
20 |
+
if ( substr( $name, 0, 5 ) == 'HTTP_' ) {
|
21 |
+
$headers[ str_replace( ' ', '-', ucwords( strtolower( str_replace( '_', ' ', substr( $name, 5 ) ) ) ) ) ] = $value;
|
22 |
+
}
|
23 |
+
}
|
24 |
+
return $headers;
|
25 |
+
}
|
26 |
+
}
|
27 |
+
|
28 |
+
class AfterShip_API_Authentication {
|
29 |
+
|
30 |
+
|
31 |
+
/**
|
32 |
+
* Setup class
|
33 |
+
*
|
34 |
+
* @since 2.1
|
35 |
+
* @return WC_API_Authentication
|
36 |
+
*/
|
37 |
+
public function __construct() {
|
38 |
+
// to disable authentication, hook into this filter at a later priority and return a valid WP_User
|
39 |
+
add_filter( 'aftership_api_check_authentication', array( $this, 'authenticate' ), 0 );
|
40 |
+
}
|
41 |
+
|
42 |
+
/**
|
43 |
+
* Authenticate the request. The authentication method varies based on whether the request was made over SSL or not.
|
44 |
+
*
|
45 |
+
* @since 2.1
|
46 |
+
* @param WP_User $user
|
47 |
+
* @return null|WP_Error|WP_User
|
48 |
+
*/
|
49 |
+
public function authenticate( $user ) {
|
50 |
+
|
51 |
+
// allow access to the index by default
|
52 |
+
if ( '/' === aftership()->api->server->path ) {
|
53 |
+
return new WP_User( 0 );
|
54 |
+
}
|
55 |
+
|
56 |
+
try {
|
57 |
+
$user = $this->perform_authentication();
|
58 |
+
|
59 |
+
} catch ( Exception $e ) {
|
60 |
+
|
61 |
+
$user = new WP_Error( 'aftership_api_authentication_error', $e->getMessage(), array( 'status' => $e->getCode() ) );
|
62 |
+
}
|
63 |
+
|
64 |
+
return $user;
|
65 |
+
}
|
66 |
+
|
67 |
+
private function perform_authentication() {
|
68 |
+
$headers = getallheaders();
|
69 |
+
$headers = json_decode( json_encode( $headers ), true );
|
70 |
+
|
71 |
+
// it dues to different kind of server configuration
|
72 |
+
$key = 'AFTERSHIP_WP_KEY';
|
73 |
+
$key1 = str_replace( ' ', '-', ucwords( strtolower( str_replace( '_', ' ', $key ) ) ) );
|
74 |
+
$key2 = 'AFTERSHIP-WP-KEY';
|
75 |
+
$qskey = isset( $_GET['key'] ) ? $_GET['key'] : null;
|
76 |
+
|
77 |
+
// get aftership wp key
|
78 |
+
if ( ! empty( $headers[ $key ] ) ) {
|
79 |
+
$api_key = $headers[ $key ];
|
80 |
+
} elseif ( ! empty( $headers[ $key1 ] ) ) {
|
81 |
+
$api_key = $headers[ $key1 ];
|
82 |
+
} elseif ( ! empty( $headers[ $key2 ] ) ) {
|
83 |
+
$api_key = $headers[ $key2 ];
|
84 |
+
} elseif ( ! empty( $qskey ) ) {
|
85 |
+
$api_key = $qskey;
|
86 |
+
} else {
|
87 |
+
throw new Exception( __( 'AfterShip\'s WordPress Key is missing', 'aftership' ), 404 );
|
88 |
+
}
|
89 |
+
|
90 |
+
$user = $this->get_user_by_api_key( $api_key );
|
91 |
+
|
92 |
+
return $user;
|
93 |
+
|
94 |
+
}
|
95 |
+
|
96 |
+
/**
|
97 |
+
* Return the user for the given consumer key
|
98 |
+
*
|
99 |
+
* @since 2.1
|
100 |
+
* @param string $consumer_key
|
101 |
+
* @return WP_User
|
102 |
+
* @throws Exception
|
103 |
+
*/
|
104 |
+
private function get_user_by_api_key( $api_key ) {
|
105 |
+
|
106 |
+
$user_query = new WP_User_Query(
|
107 |
+
array(
|
108 |
+
// 'meta_key' => 'woocommerce_api_consumer_key',
|
109 |
+
'meta_key' => 'aftership_wp_api_key',
|
110 |
+
'meta_value' => $api_key,
|
111 |
+
)
|
112 |
+
);
|
113 |
+
|
114 |
+
$users = $user_query->get_results();
|
115 |
+
|
116 |
+
if ( empty( $users[0] ) ) {
|
117 |
+
throw new Exception( __( 'AfterShip\'s WordPress API Key is invalid', 'aftership' ), 401 );
|
118 |
+
}
|
119 |
+
|
120 |
+
return $users[0];
|
121 |
+
|
122 |
+
}
|
123 |
+
|
124 |
+
}
|
{api → includes/api}/class-aftership-api-common-json-handler.php
RENAMED
File without changes
|
{api → includes/api}/class-aftership-api-json-handler.php
RENAMED
File without changes
|
includes/api/class-aftership-api-orders.php
ADDED
@@ -0,0 +1,573 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* AfterShip API Orders Class
|
4 |
+
*
|
5 |
+
* Handles requests to the /orders endpoint
|
6 |
+
*
|
7 |
+
* @author AfterShip
|
8 |
+
* @category API
|
9 |
+
* @package AfterShip/API
|
10 |
+
* @since 1.0
|
11 |
+
*/
|
12 |
+
|
13 |
+
if ( ! defined( 'ABSPATH' ) ) {
|
14 |
+
exit; // Exit if accessed directly
|
15 |
+
}
|
16 |
+
|
17 |
+
class AfterShip_API_Orders extends AfterShip_API_Resource {
|
18 |
+
|
19 |
+
|
20 |
+
/** @var string $base the route base */
|
21 |
+
protected $base = '/orders';
|
22 |
+
|
23 |
+
/**
|
24 |
+
* Register the routes for this class
|
25 |
+
*
|
26 |
+
* GET /orders
|
27 |
+
* GET /orders/count
|
28 |
+
* GET|PUT /orders/<id>
|
29 |
+
* GET /orders/<id>/notes
|
30 |
+
*
|
31 |
+
* @since 2.1
|
32 |
+
* @param array $routes
|
33 |
+
* @return array
|
34 |
+
*/
|
35 |
+
public function register_routes( $routes ) {
|
36 |
+
|
37 |
+
// GET /orders
|
38 |
+
$routes[ $this->base ] = array(
|
39 |
+
array( array( $this, 'get_orders' ), AfterShip_API_Server::READABLE ),
|
40 |
+
);
|
41 |
+
|
42 |
+
// GET /orders/count
|
43 |
+
$routes[ $this->base . '/count' ] = array(
|
44 |
+
array( array( $this, 'get_orders_count' ), AfterShip_API_Server::READABLE ),
|
45 |
+
);
|
46 |
+
|
47 |
+
// GET|PUT /orders/<id>
|
48 |
+
$routes[ $this->base . '/(?P<id>\d+)' ] = array(
|
49 |
+
array( array( $this, 'get_order' ), AfterShip_API_Server::READABLE ),
|
50 |
+
array( array( $this, 'edit_order' ), AfterShip_API_Server::EDITABLE | AfterShip_API_Server::ACCEPT_DATA ),
|
51 |
+
);
|
52 |
+
|
53 |
+
// GET /orders/<id>/notes
|
54 |
+
$routes[ $this->base . '/(?P<id>\d+)/notes' ] = array(
|
55 |
+
array( array( $this, 'get_order_notes' ), AfterShip_API_Server::READABLE ),
|
56 |
+
);
|
57 |
+
|
58 |
+
// GET /orders/ping
|
59 |
+
$routes[ $this->base . '/ping' ] = array(
|
60 |
+
array( array( $this, 'ping' ), AfterShip_API_Server::READABLE ),
|
61 |
+
);
|
62 |
+
|
63 |
+
return $routes;
|
64 |
+
}
|
65 |
+
|
66 |
+
/**
|
67 |
+
* Get all orders
|
68 |
+
*
|
69 |
+
* @since 2.1
|
70 |
+
* @param string $fields
|
71 |
+
* @param array $filter
|
72 |
+
* @param string $status
|
73 |
+
* @param int $page
|
74 |
+
* @return array
|
75 |
+
*/
|
76 |
+
public function get_orders( $fields = null, $filter = array(), $status = null, $page = 1 ) {
|
77 |
+
|
78 |
+
if ( ! empty( $status ) ) {
|
79 |
+
$filter['status'] = $status;
|
80 |
+
}
|
81 |
+
|
82 |
+
$filter['page'] = $page;
|
83 |
+
|
84 |
+
$query = $this->query_orders( $filter );
|
85 |
+
|
86 |
+
$orders = array();
|
87 |
+
|
88 |
+
foreach ( $query->posts as $order_id ) {
|
89 |
+
|
90 |
+
if ( ! $this->is_readable( $order_id ) ) {
|
91 |
+
continue;
|
92 |
+
}
|
93 |
+
|
94 |
+
$orders[] = current( $this->get_order( $order_id, $fields ) );
|
95 |
+
}
|
96 |
+
|
97 |
+
$this->server->add_pagination_headers( $query );
|
98 |
+
|
99 |
+
return array( 'orders' => $orders );
|
100 |
+
}
|
101 |
+
|
102 |
+
|
103 |
+
/**
|
104 |
+
* Get the order for the given ID
|
105 |
+
*
|
106 |
+
* @since 2.1
|
107 |
+
* @param int $id the order ID
|
108 |
+
* @param array $fields
|
109 |
+
* @return array
|
110 |
+
*/
|
111 |
+
public function get_order( $id, $fields = null ) {
|
112 |
+
|
113 |
+
// ensure order ID is valid & user has permission to read
|
114 |
+
$id = $this->validate_request( $id, 'shop_order', 'read' );
|
115 |
+
|
116 |
+
if ( is_wp_error( $id ) ) {
|
117 |
+
return $id;
|
118 |
+
}
|
119 |
+
|
120 |
+
$order = new WC_Order( $id );
|
121 |
+
|
122 |
+
$order_post = get_post( $id );
|
123 |
+
|
124 |
+
$order_id = get_order_id( $order );
|
125 |
+
|
126 |
+
$order_data = array(
|
127 |
+
'id' => get_order_id( $order ),
|
128 |
+
'order_number' => $order->get_order_number(),
|
129 |
+
'created_at' => $this->server->format_datetime( $order_post->post_date_gmt ),
|
130 |
+
'updated_at' => $this->server->format_datetime( $order_post->post_modified_gmt ),
|
131 |
+
// 'completed_at' => $this->server->format_datetime($order->completed_date, true),
|
132 |
+
// 'status' => $order->status,
|
133 |
+
// 'currency' => $order->order_currency,
|
134 |
+
// 'total' => wc_format_decimal($order->get_total(), 2),
|
135 |
+
// 'subtotal' => wc_format_decimal($this->get_order_subtotal($order), 2),
|
136 |
+
// 'total_line_items_quantity' => $order->get_item_count(),
|
137 |
+
// 'total_tax' => wc_format_decimal($order->get_total_tax(), 2),
|
138 |
+
// 'total_shipping' => wc_format_decimal($order->get_total_shipping(), 2),
|
139 |
+
// 'cart_tax' => wc_format_decimal($order->get_cart_tax(), 2),
|
140 |
+
// 'shipping_tax' => wc_format_decimal($order->get_shipping_tax(), 2),
|
141 |
+
// 'total_discount' => wc_format_decimal($order->get_total_discount(), 2),
|
142 |
+
// 'cart_discount' => wc_format_decimal($order->get_cart_discount(), 2),
|
143 |
+
// 'order_discount' => wc_format_decimal($order->get_order_discount(), 2),
|
144 |
+
// 'shipping_methods' => $order->get_shipping_method(),
|
145 |
+
// 'payment_details' => array(
|
146 |
+
// 'method_id' => $order->payment_method,
|
147 |
+
// 'method_title' => $order->payment_method_title,
|
148 |
+
// 'paid' => isset($order->paid_date),
|
149 |
+
// ),
|
150 |
+
'billing_address' => array(
|
151 |
+
'first_name' => order_post_meta_getter( $order, 'billing_first_name' ),
|
152 |
+
'last_name' => order_post_meta_getter( $order, 'billing_last_name' ),
|
153 |
+
'company' => order_post_meta_getter( $order, 'billing_company' ),
|
154 |
+
'address_1' => order_post_meta_getter( $order, 'billing_address_1' ),
|
155 |
+
'address_2' => order_post_meta_getter( $order, 'billing_address_2' ),
|
156 |
+
'city' => order_post_meta_getter( $order, 'billing_city' ),
|
157 |
+
'state' => order_post_meta_getter( $order, 'billing_state' ),
|
158 |
+
'postcode' => order_post_meta_getter( $order, 'billing_postcode' ),
|
159 |
+
'country' => order_post_meta_getter( $order, 'billing_country' ),
|
160 |
+
'email' => order_post_meta_getter( $order, 'billing_email' ),
|
161 |
+
'phone' => order_post_meta_getter( $order, 'billing_phone' ),
|
162 |
+
),
|
163 |
+
'shipping_address' => array(
|
164 |
+
'first_name' => order_post_meta_getter( $order, 'shipping_first_name' ),
|
165 |
+
'last_name' => order_post_meta_getter( $order, 'shipping_last_name' ),
|
166 |
+
'company' => order_post_meta_getter( $order, 'shipping_company' ),
|
167 |
+
'address_1' => order_post_meta_getter( $order, 'shipping_address_1' ),
|
168 |
+
'address_2' => order_post_meta_getter( $order, 'shipping_address_2' ),
|
169 |
+
'city' => order_post_meta_getter( $order, 'shipping_city' ),
|
170 |
+
'state' => order_post_meta_getter( $order, 'shipping_state' ),
|
171 |
+
'postcode' => order_post_meta_getter( $order, 'shipping_postcode' ),
|
172 |
+
'country' => order_post_meta_getter( $order, 'shipping_country' ),
|
173 |
+
),
|
174 |
+
'note' => ( method_exists( $order, 'get_customer_note' ) ) ? $order->get_customer_note() : $order->customer_note,
|
175 |
+
// 'customer_ip' => $order->customer_ip_address,
|
176 |
+
// 'customer_user_agent' => $order->customer_user_agent,
|
177 |
+
// 'customer_id' => $order->customer_user,
|
178 |
+
// 'view_order_url' => $order->get_view_order_url(),
|
179 |
+
'line_items' => array(),
|
180 |
+
// 'shipping_lines' => array(),
|
181 |
+
// 'tax_lines' => array(),
|
182 |
+
// 'fee_lines' => array(),
|
183 |
+
// 'coupon_lines' => array(),
|
184 |
+
'custom_fields' => array(),
|
185 |
+
'aftership' => array(
|
186 |
+
'woocommerce' => array(
|
187 |
+
'trackings' => array(
|
188 |
+
array(
|
189 |
+
'tracking_provider' => '',
|
190 |
+
'tracking_number' => '',
|
191 |
+
'tracking_ship_date' => '',
|
192 |
+
'tracking_postal_code' => '',
|
193 |
+
'tracking_account_number' => '',
|
194 |
+
'tracking_key' => '',
|
195 |
+
'tracking_destination_country' => '',
|
196 |
+
),
|
197 |
+
),
|
198 |
+
),
|
199 |
+
),
|
200 |
+
);
|
201 |
+
|
202 |
+
// add line items
|
203 |
+
foreach ( $order->get_items() as $item_id => $item ) {
|
204 |
+
|
205 |
+
// $product = $order->get_product_from_item($item);
|
206 |
+
|
207 |
+
$order_data['line_items'][] = array(
|
208 |
+
'id' => $item_id,
|
209 |
+
// 'subtotal' => wc_format_decimal($order->get_line_subtotal($item), 2),
|
210 |
+
// 'total' => wc_format_decimal($order->get_line_total($item), 2),
|
211 |
+
// 'total_tax' => wc_format_decimal($order->get_line_tax($item), 2),
|
212 |
+
// 'price' => wc_format_decimal($order->get_item_total($item), 2),
|
213 |
+
'quantity' => (int) $item['qty'],
|
214 |
+
// 'tax_class' => (!empty($item['tax_class'])) ? $item['tax_class'] : null,
|
215 |
+
'name' => $item['name'],
|
216 |
+
// 'product_id' => (isset($product->variation_id)) ? $product->variation_id : (method_exists($product, 'get_id'))? $product->get_id() : $product->id,
|
217 |
+
// 'sku' => is_object($product) ? $product->get_sku() : null,
|
218 |
+
);
|
219 |
+
}
|
220 |
+
|
221 |
+
/*
|
222 |
+
// add shipping
|
223 |
+
foreach ($order->get_shipping_methods() as $shipping_item_id => $shipping_item) {
|
224 |
+
|
225 |
+
$order_data['shipping_lines'][] = array(
|
226 |
+
'id' => $shipping_item_id,
|
227 |
+
'method_id' => $shipping_item['method_id'],
|
228 |
+
'method_title' => $shipping_item['name'],
|
229 |
+
'total' => wc_format_decimal($shipping_item['cost'], 2),
|
230 |
+
);
|
231 |
+
}
|
232 |
+
|
233 |
+
// add taxes
|
234 |
+
foreach ($order->get_tax_totals() as $tax_code => $tax) {
|
235 |
+
|
236 |
+
$order_data['tax_lines'][] = array(
|
237 |
+
'code' => $tax_code,
|
238 |
+
'title' => $tax->label,
|
239 |
+
'total' => wc_format_decimal($tax->amount, 2),
|
240 |
+
'compound' => (bool)$tax->is_compound,
|
241 |
+
);
|
242 |
+
}
|
243 |
+
|
244 |
+
// add fees
|
245 |
+
foreach ($order->get_fees() as $fee_item_id => $fee_item) {
|
246 |
+
|
247 |
+
$order_data['fee_lines'][] = array(
|
248 |
+
'id' => $fee_item_id,
|
249 |
+
'title' => $fee_item['name'],
|
250 |
+
'tax_class' => (!empty($fee_item['tax_class'])) ? $fee_item['tax_class'] : null,
|
251 |
+
'total' => wc_format_decimal($order->get_line_total($fee_item), 2),
|
252 |
+
'total_tax' => wc_format_decimal($order->get_line_tax($fee_item), 2),
|
253 |
+
);
|
254 |
+
}
|
255 |
+
|
256 |
+
// add coupons
|
257 |
+
foreach ($order->get_items('coupon') as $coupon_item_id => $coupon_item) {
|
258 |
+
|
259 |
+
$order_data['coupon_lines'][] = array(
|
260 |
+
'id' => $coupon_item_id,
|
261 |
+
'code' => $coupon_item['name'],
|
262 |
+
'amount' => wc_format_decimal($coupon_item['discount_amount'], 2),
|
263 |
+
);
|
264 |
+
}
|
265 |
+
*/
|
266 |
+
|
267 |
+
// aftership add
|
268 |
+
$aftership_tracking_number = order_post_meta_getter( $order, 'aftership_tracking_number' );
|
269 |
+
if ( ! empty( $aftership_tracking_number ) ) {
|
270 |
+
|
271 |
+
// $result = array();
|
272 |
+
// foreach($this->aftership_fields as $field){
|
273 |
+
// $id = $field['id'];
|
274 |
+
// $result[substr($id,10)] = get_post_meta((method_exists($order, 'get_id'))? $order->get_id() : $order->id, '_' . $field['id'], true);
|
275 |
+
// }
|
276 |
+
// $order_data['aftership']['woocommerce']['trackings'][] = $result;
|
277 |
+
|
278 |
+
$order_data['aftership']['woocommerce']['trackings'][0] = array(
|
279 |
+
'tracking_provider' => order_post_meta_getter( $order, 'aftership_tracking_provider' ),
|
280 |
+
'tracking_number' => order_post_meta_getter( $order, 'aftership_tracking_number' ),
|
281 |
+
'tracking_ship_date' => order_post_meta_getter( $order, 'aftership_tracking_shipdate' ),
|
282 |
+
'tracking_postal_code' => order_post_meta_getter( $order, 'aftership_tracking_postal' ),
|
283 |
+
'tracking_account_number' => order_post_meta_getter( $order, 'aftership_tracking_account' ),
|
284 |
+
'tracking_key' => order_post_meta_getter( $order, 'aftership_tracking_key' ),
|
285 |
+
'tracking_destination_country' => order_post_meta_getter( $order, 'aftership_tracking_destination_country' ),
|
286 |
+
);
|
287 |
+
}
|
288 |
+
if ( $tn == null ) {
|
289 |
+
// Handle old Shipping Tracking plugin
|
290 |
+
$tn = order_post_meta_getter( $order, 'tracking_number' );
|
291 |
+
if ( $tn == null ) {
|
292 |
+
// Handle new Shipping Tracking plugin version higher than 1.6.4
|
293 |
+
$tracking_items = order_post_meta_getter( $order, 'wc_shipment_tracking_items' )[0];
|
294 |
+
|
295 |
+
if ( ! empty( $tracking_items ) ) {
|
296 |
+
$order_data['aftership']['woocommerce']['trackings'][0] = array(
|
297 |
+
'tracking_number' => $tracking_items['tracking_number'],
|
298 |
+
'tracking_provider' => $tracking_items['custom_tracking_provider'],
|
299 |
+
'tracking_ship_date' => '',
|
300 |
+
'tracking_postal_code' => '',
|
301 |
+
'tracking_account_number' => '',
|
302 |
+
'tracking_key' => '',
|
303 |
+
'tracking_destination_country' => '',
|
304 |
+
);
|
305 |
+
// 获取 tracking_provider, tracking_postal_code
|
306 |
+
$trackingArr = $this->getTrackingInfoByShipmentTracking( $tracking_items );
|
307 |
+
if ( ! empty( $trackingArr ) ) {
|
308 |
+
$order_data['aftership']['woocommerce']['trackings'][0]['tracking_postal_code'] = $trackingArr['tracking_postal_code'];
|
309 |
+
$order_data['aftership']['woocommerce']['trackings'][0]['tracking_provider'] = $trackingArr['tracking_provider'];
|
310 |
+
}
|
311 |
+
}
|
312 |
+
} else {
|
313 |
+
$order_data['aftership']['woocommerce']['trackings'][0] = array(
|
314 |
+
'tracking_number' => $tn,
|
315 |
+
);
|
316 |
+
}
|
317 |
+
}
|
318 |
+
// aftership add finish
|
319 |
+
|
320 |
+
return array( 'order' => apply_filters( 'aftership_api_order_response', $order_data, $order, $fields, $this->server ) );
|
321 |
+
}
|
322 |
+
|
323 |
+
|
324 |
+
// 从wc ShipmentTracking 插件获取 Postalcode - postnl
|
325 |
+
private function getTrackingInfoByShipmentTracking( $tracking_items ) {
|
326 |
+
if ( ! isset( $tracking_items['custom_tracking_link'] ) ) {
|
327 |
+
return array();
|
328 |
+
}
|
329 |
+
|
330 |
+
// 获取 postnl Postalcode
|
331 |
+
$urlArr = parse_url( stripslashes( $tracking_items['custom_tracking_link'] ) );
|
332 |
+
|
333 |
+
if ( $urlArr === false ) {
|
334 |
+
return array();
|
335 |
+
}
|
336 |
+
|
337 |
+
if ( ! isset( $urlArr['host'] ) ) {
|
338 |
+
return array();
|
339 |
+
}
|
340 |
+
|
341 |
+
$hostArr = explode( '.', $urlArr['host'] );
|
342 |
+
$hostArrIndex = count( $hostArr ) - 2;
|
343 |
+
if ( empty( $hostArr ) || ! isset( $hostArr[ $hostArrIndex ] ) ) {
|
344 |
+
return array();
|
345 |
+
}
|
346 |
+
|
347 |
+
if ( $hostArr[ $hostArrIndex ] == 'postnl' ) {
|
348 |
+
parse_str( $urlArr['query'], $queryArr );
|
349 |
+
if ( ! isset( $queryArr['Postalcode'] ) ) {
|
350 |
+
return array();
|
351 |
+
}
|
352 |
+
|
353 |
+
return array(
|
354 |
+
'tracking_provider' => 'postnl',
|
355 |
+
'tracking_postal_code' => str_replace( ' ', '', $queryArr['Postalcode'] ),
|
356 |
+
);
|
357 |
+
}
|
358 |
+
return array();
|
359 |
+
}
|
360 |
+
|
361 |
+
|
362 |
+
/**
|
363 |
+
* Get the total number of orders
|
364 |
+
*
|
365 |
+
* @since 2.1
|
366 |
+
* @param string $status
|
367 |
+
* @param array $filter
|
368 |
+
* @return array
|
369 |
+
*/
|
370 |
+
public function get_orders_count( $status = null, $filter = array() ) {
|
371 |
+
|
372 |
+
if ( ! empty( $status ) ) {
|
373 |
+
$filter['status'] = $status;
|
374 |
+
}
|
375 |
+
|
376 |
+
$query = $this->query_orders( $filter );
|
377 |
+
|
378 |
+
if ( ! current_user_can( 'read_private_shop_orders' ) ) {
|
379 |
+
return new WP_Error( 'aftership_api_user_cannot_read_orders_count', __( 'You do not have permission to read the orders count', 'aftership' ), array( 'status' => 401 ) );
|
380 |
+
}
|
381 |
+
|
382 |
+
return array( 'count' => (int) $query->found_posts );
|
383 |
+
}
|
384 |
+
|
385 |
+
/**
|
386 |
+
* Edit an order
|
387 |
+
*
|
388 |
+
* API v1 only allows updating the status of an order
|
389 |
+
*
|
390 |
+
* @since 2.1
|
391 |
+
* @param int $id the order ID
|
392 |
+
* @param array $data
|
393 |
+
* @return array
|
394 |
+
*/
|
395 |
+
public function edit_order( $id, $data ) {
|
396 |
+
|
397 |
+
$id = $this->validate_request( $id, 'shop_order', 'edit' );
|
398 |
+
|
399 |
+
if ( is_wp_error( $id ) ) {
|
400 |
+
return $id;
|
401 |
+
}
|
402 |
+
|
403 |
+
$order = new WC_Order( $id );
|
404 |
+
|
405 |
+
if ( ! empty( $data['status'] ) ) {
|
406 |
+
|
407 |
+
$order->update_status( $data['status'], isset( $data['note'] ) ? $data['note'] : '' );
|
408 |
+
}
|
409 |
+
|
410 |
+
return $this->get_order( $id );
|
411 |
+
}
|
412 |
+
|
413 |
+
/**
|
414 |
+
* Delete an order
|
415 |
+
*
|
416 |
+
* @TODO enable along with POST in 2.2
|
417 |
+
* @param int $id the order ID
|
418 |
+
* @param bool $force true to permanently delete order, false to move to trash
|
419 |
+
* @return array
|
420 |
+
*/
|
421 |
+
public function delete_order( $id, $force = false ) {
|
422 |
+
|
423 |
+
$id = $this->validate_request( $id, 'shop_order', 'delete' );
|
424 |
+
|
425 |
+
return $this->delete( $id, 'order', ( 'true' === $force ) );
|
426 |
+
}
|
427 |
+
|
428 |
+
/**
|
429 |
+
* Get the admin order notes for an order
|
430 |
+
*
|
431 |
+
* @since 2.1
|
432 |
+
* @param int $id the order ID
|
433 |
+
* @param string $fields fields to include in response
|
434 |
+
* @return array
|
435 |
+
*/
|
436 |
+
public function get_order_notes( $id, $fields = null ) {
|
437 |
+
|
438 |
+
// ensure ID is valid order ID
|
439 |
+
$id = $this->validate_request( $id, 'shop_order', 'read' );
|
440 |
+
|
441 |
+
if ( is_wp_error( $id ) ) {
|
442 |
+
return $id;
|
443 |
+
}
|
444 |
+
|
445 |
+
$args = array(
|
446 |
+
'post_id' => $id,
|
447 |
+
'approve' => 'approve',
|
448 |
+
'type' => 'order_note',
|
449 |
+
);
|
450 |
+
|
451 |
+
remove_filter( 'comments_clauses', array( 'WC_Comments', 'exclude_order_comments' ), 10, 1 );
|
452 |
+
|
453 |
+
$notes = get_comments( $args );
|
454 |
+
|
455 |
+
add_filter( 'comments_clauses', array( 'WC_Comments', 'exclude_order_comments' ), 10, 1 );
|
456 |
+
|
457 |
+
$order_notes = array();
|
458 |
+
|
459 |
+
foreach ( $notes as $note ) {
|
460 |
+
|
461 |
+
$order_notes[] = array(
|
462 |
+
'id' => $note->comment_ID,
|
463 |
+
'created_at' => $this->server->format_datetime( $note->comment_date_gmt ),
|
464 |
+
'note' => $note->comment_content,
|
465 |
+
'customer_note' => get_comment_meta( $note->comment_ID, 'is_customer_note', true ) ? true : false,
|
466 |
+
);
|
467 |
+
}
|
468 |
+
|
469 |
+
return array( 'order_notes' => apply_filters( 'aftership_api_order_notes_response', $order_notes, $id, $fields, $notes, $this->server ) );
|
470 |
+
}
|
471 |
+
|
472 |
+
/**
|
473 |
+
* Helper method to get order post objects
|
474 |
+
*
|
475 |
+
* @since 2.1
|
476 |
+
* @param array $args request arguments for filtering query
|
477 |
+
* @return WP_Query
|
478 |
+
*/
|
479 |
+
private function query_orders( $args ) {
|
480 |
+
|
481 |
+
function aftership_wpbo_get_woo_version_number() {
|
482 |
+
// If get_plugins() isn't available, require it
|
483 |
+
if ( ! function_exists( 'get_plugins' ) ) {
|
484 |
+
require_once( ABSPATH . 'wp-admin/includes/plugin.php' );
|
485 |
+
}
|
486 |
+
|
487 |
+
// Create the plugins folder and file variables
|
488 |
+
$plugin_folder = get_plugins( '/' . 'woocommerce' );
|
489 |
+
$plugin_file = 'woocommerce.php';
|
490 |
+
|
491 |
+
// If the plugin version number is set, return it
|
492 |
+
if ( isset( $plugin_folder[ $plugin_file ]['Version'] ) ) {
|
493 |
+
return $plugin_folder[ $plugin_file ]['Version'];
|
494 |
+
|
495 |
+
} else {
|
496 |
+
// Otherwise return null
|
497 |
+
return null;
|
498 |
+
}
|
499 |
+
}
|
500 |
+
|
501 |
+
$woo_version = aftership_wpbo_get_woo_version_number();
|
502 |
+
|
503 |
+
if ( $woo_version >= 2.2 ) {
|
504 |
+
// set base query arguments
|
505 |
+
$query_args = array(
|
506 |
+
'fields' => 'ids',
|
507 |
+
'post_type' => 'shop_order',
|
508 |
+
// 'post_status' => 'publish',
|
509 |
+
'post_status' => array_keys( wc_get_order_statuses() ),
|
510 |
+
);
|
511 |
+
} else {
|
512 |
+
// set base query arguments
|
513 |
+
$query_args = array(
|
514 |
+
'fields' => 'ids',
|
515 |
+
'post_type' => 'shop_order',
|
516 |
+
'post_status' => 'publish',
|
517 |
+
);
|
518 |
+
}
|
519 |
+
|
520 |
+
// add status argument
|
521 |
+
if ( ! empty( $args['status'] ) ) {
|
522 |
+
|
523 |
+
$statuses = explode( ',', $args['status'] );
|
524 |
+
|
525 |
+
$query_args['tax_query'] = array(
|
526 |
+
array(
|
527 |
+
'taxonomy' => 'shop_order_status',
|
528 |
+
'field' => 'slug',
|
529 |
+
'terms' => $statuses,
|
530 |
+
),
|
531 |
+
);
|
532 |
+
|
533 |
+
unset( $args['status'] );
|
534 |
+
}
|
535 |
+
|
536 |
+
$query_args = $this->merge_query_args( $query_args, $args );
|
537 |
+
|
538 |
+
return new WP_Query( $query_args );
|
539 |
+
}
|
540 |
+
|
541 |
+
/**
|
542 |
+
* Helper method to get the order subtotal
|
543 |
+
*
|
544 |
+
* @since 2.1
|
545 |
+
* @param WC_Order $order
|
546 |
+
* @return float
|
547 |
+
*/
|
548 |
+
private function get_order_subtotal( $order ) {
|
549 |
+
|
550 |
+
$subtotal = 0;
|
551 |
+
|
552 |
+
// subtotal
|
553 |
+
foreach ( $order->get_items() as $item ) {
|
554 |
+
|
555 |
+
$subtotal += ( isset( $item['line_subtotal'] ) ) ? $item['line_subtotal'] : 0;
|
556 |
+
}
|
557 |
+
|
558 |
+
return $subtotal;
|
559 |
+
}
|
560 |
+
|
561 |
+
/**
|
562 |
+
* Get the total number of orders
|
563 |
+
*
|
564 |
+
* @since 2.1
|
565 |
+
* @param string $status
|
566 |
+
* @param array $filter
|
567 |
+
* @return array
|
568 |
+
*/
|
569 |
+
public function ping() {
|
570 |
+
return 'pong';
|
571 |
+
}
|
572 |
+
|
573 |
+
}
|
includes/api/class-aftership-api-resource.php
ADDED
@@ -0,0 +1,444 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* AfterShip API Resource class
|
4 |
+
*
|
5 |
+
* Provides shared functionality for resource-specific API classes
|
6 |
+
*
|
7 |
+
* @author AfterShip
|
8 |
+
* @category API
|
9 |
+
* @package AfterShip/API
|
10 |
+
* @since 1.0
|
11 |
+
*/
|
12 |
+
|
13 |
+
if ( ! defined( 'ABSPATH' ) ) {
|
14 |
+
exit; // Exit if accessed directly
|
15 |
+
}
|
16 |
+
|
17 |
+
class AfterShip_API_Resource {
|
18 |
+
|
19 |
+
|
20 |
+
/** @var WC_API_Server the API server */
|
21 |
+
protected $server;
|
22 |
+
|
23 |
+
/** @var string sub-classes override this to set a resource-specific base route */
|
24 |
+
protected $base;
|
25 |
+
|
26 |
+
/**
|
27 |
+
* Setup class
|
28 |
+
*
|
29 |
+
* @since 2.1
|
30 |
+
* @param WC_API_Server $server
|
31 |
+
* @return WC_API_Resource
|
32 |
+
*/
|
33 |
+
public function __construct( AfterShip_API_Server $server ) {
|
34 |
+
|
35 |
+
$this->server = $server;
|
36 |
+
|
37 |
+
// automatically register routes for sub-classes
|
38 |
+
add_filter( 'aftership_api_endpoints', array( $this, 'register_routes' ) );
|
39 |
+
|
40 |
+
// remove fields from responses when requests specify certain fields
|
41 |
+
// note these are hooked at a later priority so data added via filters (e.g. customer data to the order response)
|
42 |
+
// still has the fields filtered properly
|
43 |
+
foreach ( array( 'order', 'coupon', 'customer', 'product', 'report' ) as $resource ) {
|
44 |
+
|
45 |
+
add_filter( "aftership_api_{$resource}_response", array( $this, 'maybe_add_meta' ), 15, 2 );
|
46 |
+
add_filter( "aftership_api_{$resource}_response", array( $this, 'filter_response_fields' ), 20, 3 );
|
47 |
+
}
|
48 |
+
}
|
49 |
+
|
50 |
+
/**
|
51 |
+
* Validate the request by checking:
|
52 |
+
*
|
53 |
+
* 1) the ID is a valid integer
|
54 |
+
* 2) the ID returns a valid post object and matches the provided post type
|
55 |
+
* 3) the current user has the proper permissions to read/edit/delete the post
|
56 |
+
*
|
57 |
+
* @since 2.1
|
58 |
+
* @param string|int $id the post ID
|
59 |
+
* @param string $type the post type, either `shop_order`, `shop_coupon`, or `product`
|
60 |
+
* @param string $context the context of the request, either `read`, `edit` or `delete`
|
61 |
+
* @return int|WP_Error valid post ID or WP_Error if any of the checks fails
|
62 |
+
*/
|
63 |
+
protected function validate_request( $id, $type, $context ) {
|
64 |
+
|
65 |
+
if ( 'shop_order' === $type || 'shop_coupon' === $type ) {
|
66 |
+
$resource_name = str_replace( 'shop_', '', $type );
|
67 |
+
} else {
|
68 |
+
$resource_name = $type;
|
69 |
+
}
|
70 |
+
|
71 |
+
$id = absint( $id );
|
72 |
+
|
73 |
+
// validate ID
|
74 |
+
if ( empty( $id ) ) {
|
75 |
+
return new WP_Error( "aftership_api_invalid_{$resource_name}_id", sprintf( __( 'Invalid %s ID', 'aftership' ), $type ), array( 'status' => 404 ) );
|
76 |
+
}
|
77 |
+
|
78 |
+
// only custom post types have per-post type/permission checks
|
79 |
+
if ( 'customer' !== $type ) {
|
80 |
+
|
81 |
+
$post = get_post( $id );
|
82 |
+
|
83 |
+
// for checking permissions, product variations are the same as the product post type
|
84 |
+
$post_type = ( 'product_variation' === $post->post_type ) ? 'product' : $post->post_type;
|
85 |
+
|
86 |
+
// validate post type
|
87 |
+
if ( $type !== $post_type ) {
|
88 |
+
return new WP_Error( "aftership_api_invalid_{$resource_name}", sprintf( __( 'Invalid %s', 'aftership' ), $resource_name ), array( 'status' => 404 ) );
|
89 |
+
}
|
90 |
+
|
91 |
+
// validate permissions
|
92 |
+
switch ( $context ) {
|
93 |
+
|
94 |
+
case 'read':
|
95 |
+
if ( ! $this->is_readable( $post ) ) {
|
96 |
+
return new WP_Error( "aftership_api_user_cannot_read_{$resource_name}", sprintf( __( 'You do not have permission to read this %s', 'aftership' ), $resource_name ), array( 'status' => 401 ) );
|
97 |
+
}
|
98 |
+
break;
|
99 |
+
|
100 |
+
case 'edit':
|
101 |
+
if ( ! $this->is_editable( $post ) ) {
|
102 |
+
return new WP_Error( "aftership_api_user_cannot_edit_{$resource_name}", sprintf( __( 'You do not have permission to edit this %s', 'aftership' ), $resource_name ), array( 'status' => 401 ) );
|
103 |
+
}
|
104 |
+
break;
|
105 |
+
|
106 |
+
case 'delete':
|
107 |
+
if ( ! $this->is_deletable( $post ) ) {
|
108 |
+
return new WP_Error( "aftership_api_user_cannot_delete_{$resource_name}", sprintf( __( 'You do not have permission to delete this %s', 'aftership' ), $resource_name ), array( 'status' => 401 ) );
|
109 |
+
}
|
110 |
+
break;
|
111 |
+
}
|
112 |
+
}
|
113 |
+
|
114 |
+
return $id;
|
115 |
+
}
|
116 |
+
|
117 |
+
/**
|
118 |
+
* Add common request arguments to argument list before WP_Query is run
|
119 |
+
*
|
120 |
+
* @since 2.1
|
121 |
+
* @param array $base_args required arguments for the query (e.g. `post_type`, etc)
|
122 |
+
* @param array $request_args arguments provided in the request
|
123 |
+
* @return array
|
124 |
+
*/
|
125 |
+
protected function merge_query_args( $base_args, $request_args ) {
|
126 |
+
|
127 |
+
$args = array();
|
128 |
+
|
129 |
+
// date
|
130 |
+
if ( ! empty( $request_args['created_at_min'] ) || ! empty( $request_args['created_at_max'] ) || ! empty( $request_args['updated_at_min'] ) || ! empty( $request_args['updated_at_max'] ) ) {
|
131 |
+
|
132 |
+
$args['date_query'] = array();
|
133 |
+
|
134 |
+
// resources created after specified date
|
135 |
+
if ( ! empty( $request_args['created_at_min'] ) ) {
|
136 |
+
$args['date_query'][] = array(
|
137 |
+
'column' => 'post_date_gmt',
|
138 |
+
'after' => $this->server->parse_datetime( $request_args['created_at_min'] ),
|
139 |
+
'inclusive' => true,
|
140 |
+
);
|
141 |
+
}
|
142 |
+
|
143 |
+
// resources created before specified date
|
144 |
+
if ( ! empty( $request_args['created_at_max'] ) ) {
|
145 |
+
$args['date_query'][] = array(
|
146 |
+
'column' => 'post_date_gmt',
|
147 |
+
'before' => $this->server->parse_datetime( $request_args['created_at_max'] ),
|
148 |
+
'inclusive' => true,
|
149 |
+
);
|
150 |
+
}
|
151 |
+
|
152 |
+
// resources updated after specified date
|
153 |
+
if ( ! empty( $request_args['updated_at_min'] ) ) {
|
154 |
+
$args['date_query'][] = array(
|
155 |
+
'column' => 'post_modified_gmt',
|
156 |
+
'after' => $this->server->parse_datetime( $request_args['updated_at_min'] ),
|
157 |
+
'inclusive' => true,
|
158 |
+
);
|
159 |
+
}
|
160 |
+
|
161 |
+
// resources updated before specified date
|
162 |
+
if ( ! empty( $request_args['updated_at_max'] ) ) {
|
163 |
+
$args['date_query'][] = array(
|
164 |
+
'column' => 'post_modified_gmt',
|
165 |
+
'before' => $this->server->parse_datetime( $request_args['updated_at_max'] ),
|
166 |
+
'inclusive' => true,
|
167 |
+
);
|
168 |
+
}
|
169 |
+
}
|
170 |
+
|
171 |
+
// search
|
172 |
+
if ( ! empty( $request_args['q'] ) ) {
|
173 |
+
$args['s'] = $request_args['q'];
|
174 |
+
}
|
175 |
+
|
176 |
+
// resources per response
|
177 |
+
if ( ! empty( $request_args['limit'] ) ) {
|
178 |
+
$args['posts_per_page'] = $request_args['limit'];
|
179 |
+
}
|
180 |
+
|
181 |
+
// resource offset
|
182 |
+
if ( ! empty( $request_args['offset'] ) ) {
|
183 |
+
$args['offset'] = $request_args['offset'];
|
184 |
+
}
|
185 |
+
|
186 |
+
// resource page
|
187 |
+
$args['paged'] = ( isset( $request_args['page'] ) ) ? absint( $request_args['page'] ) : 1;
|
188 |
+
|
189 |
+
// order
|
190 |
+
if ( ! empty( $request_args['orderby'] ) ) {
|
191 |
+
$args['orderby'] = $request_args['orderby'];
|
192 |
+
}
|
193 |
+
if ( ! empty( $request_args['order'] ) ) {
|
194 |
+
$args['order'] = $request_args['order'];
|
195 |
+
}
|
196 |
+
|
197 |
+
return array_merge( $base_args, $args );
|
198 |
+
}
|
199 |
+
|
200 |
+
/**
|
201 |
+
* Add meta to resources when requested by the client. Meta is added as a top-level
|
202 |
+
* `<resource_name>_meta` attribute (e.g. `order_meta`) as a list of key/value pairs
|
203 |
+
*
|
204 |
+
* @since 2.1
|
205 |
+
* @param array $data the resource data
|
206 |
+
* @param object $resource the resource object (e.g WC_Order)
|
207 |
+
* @return mixed
|
208 |
+
*/
|
209 |
+
public function maybe_add_meta( $data, $resource ) {
|
210 |
+
|
211 |
+
if ( isset( $this->server->params['GET']['filter']['meta'] ) && 'true' === $this->server->params['GET']['filter']['meta'] && is_object( $resource ) ) {
|
212 |
+
|
213 |
+
// don't attempt to add meta more than once
|
214 |
+
if ( preg_grep( '/[a-z]+_meta/', array_keys( $data ) ) ) {
|
215 |
+
return $data;
|
216 |
+
}
|
217 |
+
|
218 |
+
// define the top-level property name for the meta
|
219 |
+
switch ( get_class( $resource ) ) {
|
220 |
+
|
221 |
+
case 'WC_Order':
|
222 |
+
$meta_name = 'order_meta';
|
223 |
+
break;
|
224 |
+
|
225 |
+
case 'WC_Coupon':
|
226 |
+
$meta_name = 'coupon_meta';
|
227 |
+
break;
|
228 |
+
|
229 |
+
case 'WP_User':
|
230 |
+
$meta_name = 'customer_meta';
|
231 |
+
break;
|
232 |
+
|
233 |
+
default:
|
234 |
+
$meta_name = 'product_meta';
|
235 |
+
break;
|
236 |
+
}
|
237 |
+
|
238 |
+
if ( is_a( $resource, 'WP_User' ) ) {
|
239 |
+
|
240 |
+
// customer meta
|
241 |
+
$meta = (array) get_user_meta( $resource->ID );
|
242 |
+
|
243 |
+
} elseif ( is_a( $resource, 'WC_Product_Variation' ) ) {
|
244 |
+
|
245 |
+
// product variation meta
|
246 |
+
$meta = (array) get_post_meta( $resource->get_variation_id() );
|
247 |
+
|
248 |
+
} else {
|
249 |
+
|
250 |
+
// coupon/order/product meta
|
251 |
+
$meta = (array) get_post_meta( $resource->id );
|
252 |
+
}
|
253 |
+
|
254 |
+
foreach ( $meta as $meta_key => $meta_value ) {
|
255 |
+
|
256 |
+
// don't add hidden meta by default
|
257 |
+
if ( ! is_protected_meta( $meta_key ) ) {
|
258 |
+
$data[ $meta_name ][ $meta_key ] = maybe_unserialize( $meta_value[0] );
|
259 |
+
}
|
260 |
+
}
|
261 |
+
}
|
262 |
+
|
263 |
+
return $data;
|
264 |
+
}
|
265 |
+
|
266 |
+
/**
|
267 |
+
* Restrict the fields included in the response if the request specified certain only certain fields should be returned
|
268 |
+
*
|
269 |
+
* @since 2.1
|
270 |
+
* @param array $data the response data
|
271 |
+
* @param object $resource the object that provided the response data, e.g. WC_Coupon or WC_Order
|
272 |
+
* @param array|string the requested list of fields to include in the response
|
273 |
+
* @return array response data
|
274 |
+
*/
|
275 |
+
public function filter_response_fields( $data, $resource, $fields ) {
|
276 |
+
|
277 |
+
if ( ! is_array( $data ) || empty( $fields ) ) {
|
278 |
+
return $data;
|
279 |
+
}
|
280 |
+
|
281 |
+
$fields = explode( ',', $fields );
|
282 |
+
$sub_fields = array();
|
283 |
+
|
284 |
+
// get sub fields
|
285 |
+
foreach ( $fields as $field ) {
|
286 |
+
|
287 |
+
if ( false !== strpos( $field, '.' ) ) {
|
288 |
+
|
289 |
+
list($name, $value) = explode( '.', $field );
|
290 |
+
|
291 |
+
$sub_fields[ $name ] = $value;
|
292 |
+
}
|
293 |
+
}
|
294 |
+
|
295 |
+
// iterate through top-level fields
|
296 |
+
foreach ( $data as $data_field => $data_value ) {
|
297 |
+
|
298 |
+
// if a field has sub-fields and the top-level field has sub-fields to filter
|
299 |
+
if ( is_array( $data_value ) && in_array( $data_field, array_keys( $sub_fields ) ) ) {
|
300 |
+
|
301 |
+
// iterate through each sub-field
|
302 |
+
foreach ( $data_value as $sub_field => $sub_field_value ) {
|
303 |
+
|
304 |
+
// remove non-matching sub-fields
|
305 |
+
if ( ! in_array( $sub_field, $sub_fields ) ) {
|
306 |
+
unset( $data[ $data_field ][ $sub_field ] );
|
307 |
+
}
|
308 |
+
}
|
309 |
+
} else {
|
310 |
+
|
311 |
+
// remove non-matching top-level fields
|
312 |
+
if ( ! in_array( $data_field, $fields ) ) {
|
313 |
+
unset( $data[ $data_field ] );
|
314 |
+
}
|
315 |
+
}
|
316 |
+
}
|
317 |
+
|
318 |
+
return $data;
|
319 |
+
}
|
320 |
+
|
321 |
+
/**
|
322 |
+
* Delete a given resource
|
323 |
+
*
|
324 |
+
* @since 2.1
|
325 |
+
* @param int $id the resource ID
|
326 |
+
* @param string $type the resource post type, or `customer`
|
327 |
+
* @param bool $force true to permanently delete resource, false to move to trash (not supported for `customer`)
|
328 |
+
* @return array|WP_Error
|
329 |
+
*/
|
330 |
+
protected function delete( $id, $type, $force = false ) {
|
331 |
+
|
332 |
+
if ( 'shop_order' === $type || 'shop_coupon' === $type ) {
|
333 |
+
$resource_name = str_replace( 'shop_', '', $type );
|
334 |
+
} else {
|
335 |
+
$resource_name = $type;
|
336 |
+
}
|
337 |
+
|
338 |
+
if ( 'customer' === $type ) {
|
339 |
+
|
340 |
+
$result = wp_delete_user( $id );
|
341 |
+
|
342 |
+
if ( $result ) {
|
343 |
+
return array( 'message' => __( 'Permanently deleted customer', 'aftership' ) );
|
344 |
+
} else {
|
345 |
+
return new WP_Error( 'aftership_api_cannot_delete_customer', __( 'The customer cannot be deleted', 'aftership' ), array( 'status' => 500 ) );
|
346 |
+
}
|
347 |
+
} else {
|
348 |
+
|
349 |
+
// delete order/coupon/product
|
350 |
+
|
351 |
+
$result = ( $force ) ? wp_delete_post( $id, true ) : wp_trash_post( $id );
|
352 |
+
|
353 |
+
if ( ! $result ) {
|
354 |
+
return new WP_Error( "aftership_api_cannot_delete_{$resource_name}", sprintf( __( 'This %s cannot be deleted', 'aftership' ), $resource_name ), array( 'status' => 500 ) );
|
355 |
+
}
|
356 |
+
|
357 |
+
if ( $force ) {
|
358 |
+
return array( 'message' => sprintf( __( 'Permanently deleted %s', 'aftership' ), $resource_name ) );
|
359 |
+
|
360 |
+
} else {
|
361 |
+
|
362 |
+
$this->server->send_status( '202' );
|
363 |
+
|
364 |
+
return array( 'message' => sprintf( __( 'Deleted %s', 'aftership' ), $resource_name ) );
|
365 |
+
}
|
366 |
+
}
|
367 |
+
}
|
368 |
+
|
369 |
+
|
370 |
+
/**
|
371 |
+
* Checks if the given post is readable by the current user
|
372 |
+
*
|
373 |
+
* @since 2.1
|
374 |
+
* @see WC_API_Resource::check_permission()
|
375 |
+
* @param WP_Post|int $post
|
376 |
+
* @return bool
|
377 |
+
*/
|
378 |
+
protected function is_readable( $post ) {
|
379 |
+
|
380 |
+
return $this->check_permission( $post, 'read' );
|
381 |
+
}
|
382 |
+
|
383 |
+
/**
|
384 |
+
* Checks if the given post is editable by the current user
|
385 |
+
*
|
386 |
+
* @since 2.1
|
387 |
+
* @see WC_API_Resource::check_permission()
|
388 |
+
* @param WP_Post|int $post
|
389 |
+
* @return bool
|
390 |
+
*/
|
391 |
+
protected function is_editable( $post ) {
|
392 |
+
|
393 |
+
return $this->check_permission( $post, 'edit' );
|
394 |
+
|
395 |
+
}
|
396 |
+
|
397 |
+
/**
|
398 |
+
* Checks if the given post is deletable by the current user
|
399 |
+
*
|
400 |
+
* @since 2.1
|
401 |
+
* @see WC_API_Resource::check_permission()
|
402 |
+
* @param WP_Post|int $post
|
403 |
+
* @return bool
|
404 |
+
*/
|
405 |
+
protected function is_deletable( $post ) {
|
406 |
+
|
407 |
+
return $this->check_permission( $post, 'delete' );
|
408 |
+
}
|
409 |
+
|
410 |
+
/**
|
411 |
+
* Checks the permissions for the current user given a post and context
|
412 |
+
*
|
413 |
+
* @since 2.1
|
414 |
+
* @param WP_Post|int $post
|
415 |
+
* @param string $context the type of permission to check, either `read`, `write`, or `delete`
|
416 |
+
* @return bool true if the current user has the permissions to perform the context on the post
|
417 |
+
*/
|
418 |
+
private function check_permission( $post, $context ) {
|
419 |
+
|
420 |
+
if ( ! is_a( $post, 'WP_Post' ) ) {
|
421 |
+
$post = get_post( $post );
|
422 |
+
}
|
423 |
+
|
424 |
+
if ( is_null( $post ) ) {
|
425 |
+
return false;
|
426 |
+
}
|
427 |
+
|
428 |
+
$post_type = get_post_type_object( $post->post_type );
|
429 |
+
|
430 |
+
if ( 'read' === $context ) {
|
431 |
+
return current_user_can( $post_type->cap->read_private_posts, $post->ID );
|
432 |
+
|
433 |
+
} elseif ( 'edit' === $context ) {
|
434 |
+
return current_user_can( $post_type->cap->edit_post, $post->ID );
|
435 |
+
|
436 |
+
} elseif ( 'delete' === $context ) {
|
437 |
+
return current_user_can( $post_type->cap->delete_post, $post->ID );
|
438 |
+
|
439 |
+
} else {
|
440 |
+
return false;
|
441 |
+
}
|
442 |
+
}
|
443 |
+
|
444 |
+
}
|
includes/api/class-aftership-api-server.php
ADDED
@@ -0,0 +1,1041 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* AfterShip API
|
4 |
+
*
|
5 |
+
* Handles REST API requests
|
6 |
+
*
|
7 |
+
* This class and related code (JSON response handler, resource classes) are based on WP-API v0.6 (https://github.com/WP-API/WP-API)
|
8 |
+
* Many thanks to Ryan McCue and any other contributors!
|
9 |
+
*
|
10 |
+
* @author AfterShip
|
11 |
+
* @category API
|
12 |
+
* @package AfterShip/API
|
13 |
+
* @since 1.0
|
14 |
+
*/
|
15 |
+
|
16 |
+
if ( ! defined( 'ABSPATH' ) ) {
|
17 |
+
exit; // Exit if accessed directly
|
18 |
+
}
|
19 |
+
|
20 |
+
require_once ABSPATH . 'wp-admin/includes/admin.php';
|
21 |
+
|
22 |
+
class AfterShip_API_Server {
|
23 |
+
|
24 |
+
|
25 |
+
const METHOD_GET = 1;
|
26 |
+
const METHOD_POST = 2;
|
27 |
+
const METHOD_PUT = 4;
|
28 |
+
const METHOD_PATCH = 8;
|
29 |
+
const METHOD_DELETE = 16;
|
30 |
+
|
31 |
+
const READABLE = 1; // GET
|
32 |
+
const CREATABLE = 2; // POST
|
33 |
+
const EDITABLE = 14; // POST | PUT | PATCH
|
34 |
+
const DELETABLE = 16; // DELETE
|
35 |
+
const ALLMETHODS = 31; // GET | POST | PUT | PATCH | DELETE
|
36 |
+
|
37 |
+
/**
|
38 |
+
* Does the endpoint accept a raw request body?
|
39 |
+
*/
|
40 |
+
const ACCEPT_RAW_DATA = 64;
|
41 |
+
|
42 |
+
/** Does the endpoint accept a request body? (either JSON or XML) */
|
43 |
+
const ACCEPT_DATA = 128;
|
44 |
+
|
45 |
+
/**
|
46 |
+
* Should we hide this endpoint from the index?
|
47 |
+
*/
|
48 |
+
const HIDDEN_ENDPOINT = 256;
|
49 |
+
|
50 |
+
/**
|
51 |
+
* Map of HTTP verbs to constants
|
52 |
+
*
|
53 |
+
* @var array
|
54 |
+
*/
|
55 |
+
public static $method_map = array(
|
56 |
+
'HEAD' => self::METHOD_GET,
|
57 |
+
'GET' => self::METHOD_GET,
|
58 |
+
'POST' => self::METHOD_POST,
|
59 |
+
'PUT' => self::METHOD_PUT,
|
60 |
+
'PATCH' => self::METHOD_PATCH,
|
61 |
+
'DELETE' => self::METHOD_DELETE,
|
62 |
+
);
|
63 |
+
|
64 |
+
/**
|
65 |
+
* Requested path (relative to the API root, wp-json.php)
|
66 |
+
*
|
67 |
+
* @var string
|
68 |
+
*/
|
69 |
+
public $path = '';
|
70 |
+
|
71 |
+
/**
|
72 |
+
* Requested method (GET/HEAD/POST/PUT/PATCH/DELETE)
|
73 |
+
*
|
74 |
+
* @var string
|
75 |
+
*/
|
76 |
+
public $method = 'HEAD';
|
77 |
+
|
78 |
+
/**
|
79 |
+
* Request parameters
|
80 |
+
*
|
81 |
+
* This acts as an abstraction of the superglobals
|
82 |
+
* (GET => $_GET, POST => $_POST)
|
83 |
+
*
|
84 |
+
* @var array
|
85 |
+
*/
|
86 |
+
public $params = array(
|
87 |
+
'GET' => array(),
|
88 |
+
'POST' => array(),
|
89 |
+
);
|
90 |
+
|
91 |
+
/**
|
92 |
+
* Request headers
|
93 |
+
*
|
94 |
+
* @var array
|
95 |
+
*/
|
96 |
+
public $headers = array();
|
97 |
+
|
98 |
+
/**
|
99 |
+
* Request files (matches $_FILES)
|
100 |
+
*
|
101 |
+
* @var array
|
102 |
+
*/
|
103 |
+
public $files = array();
|
104 |
+
|
105 |
+
/**
|
106 |
+
* Request/Response handler, either JSON by default
|
107 |
+
* or XML if requested by client
|
108 |
+
*
|
109 |
+
* @var WC_API_Handler
|
110 |
+
*/
|
111 |
+
public $handler;
|
112 |
+
|
113 |
+
|
114 |
+
/**
|
115 |
+
* Setup class and set request/response handler
|
116 |
+
*
|
117 |
+
* @since 2.1
|
118 |
+
* @param $path
|
119 |
+
* @return WC_API_Server
|
120 |
+
*/
|
121 |
+
public function __construct( $path ) {
|
122 |
+
|
123 |
+
if ( empty( $path ) ) {
|
124 |
+
if ( isset( $_SERVER['PATH_INFO'] ) ) {
|
125 |
+
$path = $_SERVER['PATH_INFO'];
|
126 |
+
} else {
|
127 |
+
$path = '/';
|
128 |
+
}
|
129 |
+
}
|
130 |
+
|
131 |
+
$this->path = $path;
|
132 |
+
$this->method = $_SERVER['REQUEST_METHOD'];
|
133 |
+
$this->params['GET'] = $_GET;
|
134 |
+
$this->params['POST'] = $_POST;
|
135 |
+
$this->headers = $this->get_headers( $_SERVER );
|
136 |
+
$this->files = $_FILES;
|
137 |
+
|
138 |
+
// Compatibility for clients that can't use PUT/PATCH/DELETE
|
139 |
+
if ( isset( $_GET['_method'] ) ) {
|
140 |
+
$this->method = strtoupper( $_GET['_method'] );
|
141 |
+
}
|
142 |
+
|
143 |
+
// determine type of request/response and load handler, JSON by default
|
144 |
+
if ( $this->is_json_request() ) {
|
145 |
+
$handler_class = 'AfterShip_API_JSON_Handler';
|
146 |
+
} elseif ( $this->is_xml_request() ) {
|
147 |
+
$handler_class = 'WC_API_XML_Handler';
|
148 |
+
} else {
|
149 |
+
$handler_class = apply_filters( 'aftership_api_default_response_handler', 'AfterShip_API_JSON_Handler', $this->path, $this );
|
150 |
+
}
|
151 |
+
if ( ! $this->is_legacy() ) {
|
152 |
+
$handler_class = 'AfterShip_API_Common_JSON_Handler';
|
153 |
+
}
|
154 |
+
$this->handler = new $handler_class();
|
155 |
+
}
|
156 |
+
|
157 |
+
public function is_legacy() {
|
158 |
+
// check path
|
159 |
+
if ( false !== stripos( $this->path, '/v' ) ) {
|
160 |
+
return false;
|
161 |
+
}
|
162 |
+
return true;
|
163 |
+
}
|
164 |
+
|
165 |
+
/**
|
166 |
+
* Check authentication for the request
|
167 |
+
*
|
168 |
+
* @since 2.1
|
169 |
+
* @return WP_User|WP_Error WP_User object indicates successful login, WP_Error indicates unsuccessful login
|
170 |
+
*/
|
171 |
+
public function check_authentication() {
|
172 |
+
// allow plugins to remove default authentication or add their own authentication
|
173 |
+
$user = apply_filters( 'aftership_api_check_authentication', null, $this );
|
174 |
+
|
175 |
+
// API requests run under the context of the authenticated user
|
176 |
+
if ( is_a( $user, 'WP_User' ) ) {
|
177 |
+
wp_set_current_user( $user->ID );
|
178 |
+
}
|
179 |
+
|
180 |
+
// WP_Errors are handled in serve_request()
|
181 |
+
elseif ( ! is_wp_error( $user ) ) {
|
182 |
+
$user = new WP_Error( 'aftership_api_authentication_error', __( 'Invalid authentication method', 'aftership' ), array( 'code' => 500 ) );
|
183 |
+
}
|
184 |
+
|
185 |
+
return $user;
|
186 |
+
}
|
187 |
+
|
188 |
+
/**
|
189 |
+
* Convert an error to an array
|
190 |
+
*
|
191 |
+
* This iterates over all error codes and messages to change it into a flat
|
192 |
+
* array. This enables simpler client behaviour, as it is represented as a
|
193 |
+
* list in JSON rather than an object/map
|
194 |
+
*
|
195 |
+
* @since 2.1
|
196 |
+
* @param WP_Error $error
|
197 |
+
* @return array List of associative arrays with code and message keys
|
198 |
+
*/
|
199 |
+
protected function error_to_array( $error ) {
|
200 |
+
$errors = array();
|
201 |
+
foreach ( (array) $error->errors as $code => $messages ) {
|
202 |
+
foreach ( (array) $messages as $message ) {
|
203 |
+
$errors[] = array(
|
204 |
+
'code' => $code,
|
205 |
+
'message' => $message,
|
206 |
+
);
|
207 |
+
}
|
208 |
+
}
|
209 |
+
return array( 'errors' => $errors );
|
210 |
+
}
|
211 |
+
|
212 |
+
/**
|
213 |
+
* Handle serving an API request
|
214 |
+
*
|
215 |
+
* Matches the current server URI to a route and runs the first matching
|
216 |
+
* callback then outputs a JSON representation of the returned value.
|
217 |
+
*
|
218 |
+
* @since 2.1
|
219 |
+
* @uses WC_API_Server::dispatch()
|
220 |
+
*/
|
221 |
+
public function serve_request() {
|
222 |
+
do_action( 'aftership_api_server_before_serve', $this );
|
223 |
+
|
224 |
+
$this->header( 'Content-Type', $this->handler->get_content_type(), true );
|
225 |
+
|
226 |
+
// the API is enabled by default
|
227 |
+
if ( ! apply_filters( 'aftership_api_enabled', true, $this ) || ( 'no' === get_option( 'aftership_api_enabled' ) ) ) {
|
228 |
+
|
229 |
+
$this->send_status( 404 );
|
230 |
+
|
231 |
+
echo $this->handler->generate_response(
|
232 |
+
array(
|
233 |
+
'errors' => array(
|
234 |
+
'code' => 'aftership_api_disabled',
|
235 |
+
'message' => 'The WooCommerce API is disabled on this site',
|
236 |
+
),
|
237 |
+
)
|
238 |
+
);
|
239 |
+
|
240 |
+
return;
|
241 |
+
}
|
242 |
+
|
243 |
+
$result = $this->check_authentication();
|
244 |
+
|
245 |
+
// if authorization check was successful, dispatch the request
|
246 |
+
if ( ! is_wp_error( $result ) ) {
|
247 |
+
$result = $this->dispatch();
|
248 |
+
}
|
249 |
+
|
250 |
+
// handle any dispatch errors
|
251 |
+
if ( is_wp_error( $result ) ) {
|
252 |
+
$data = $result->get_error_data();
|
253 |
+
if ( is_array( $data ) && isset( $data['status'] ) ) {
|
254 |
+
$this->send_status( $data['status'] );
|
255 |
+
}
|
256 |
+
|
257 |
+
$result = $this->error_to_array( $result );
|
258 |
+
}
|
259 |
+
|
260 |
+
// This is a filter rather than an action, since this is designed to be
|
261 |
+
// re-entrant if needed
|
262 |
+
$served = apply_filters( 'aftership_api_serve_request', false, $result, $this );
|
263 |
+
|
264 |
+
if ( ! $served ) {
|
265 |
+
|
266 |
+
if ( 'HEAD' === $this->method ) {
|
267 |
+
return;
|
268 |
+
}
|
269 |
+
|
270 |
+
echo $this->handler->generate_response( $result );
|
271 |
+
}
|
272 |
+
}
|
273 |
+
|
274 |
+
/**
|
275 |
+
* Retrieve the route map
|
276 |
+
*
|
277 |
+
* The route map is an associative array with path regexes as the keys. The
|
278 |
+
* value is an indexed array with the callback function/method as the first
|
279 |
+
* item, and a bitmask of HTTP methods as the second item (see the class
|
280 |
+
* constants).
|
281 |
+
*
|
282 |
+
* Each route can be mapped to more than one callback by using an array of
|
283 |
+
* the indexed arrays. This allows mapping e.g. GET requests to one callback
|
284 |
+
* and POST requests to another.
|
285 |
+
*
|
286 |
+
* Note that the path regexes (array keys) must have @ escaped, as this is
|
287 |
+
* used as the delimiter with preg_match()
|
288 |
+
*
|
289 |
+
* @since 2.1
|
290 |
+
* @return array `'/path/regex' => array( $callback, $bitmask )` or `'/path/regex' => array( array( $callback, $bitmask ), ...)`
|
291 |
+
*/
|
292 |
+
public function get_routes() {
|
293 |
+
// index added by default
|
294 |
+
$endpoints = array(
|
295 |
+
|
296 |
+
'/' => array( array( $this, 'get_index' ), self::READABLE ),
|
297 |
+
);
|
298 |
+
|
299 |
+
$endpoints = apply_filters( 'aftership_api_endpoints', $endpoints );
|
300 |
+
|
301 |
+
// Normalise the endpoints
|
302 |
+
foreach ( $endpoints as $route => &$handlers ) {
|
303 |
+
if ( count( $handlers ) <= 2 && isset( $handlers[1] ) && ! is_array( $handlers[1] ) ) {
|
304 |
+
$handlers = array( $handlers );
|
305 |
+
}
|
306 |
+
}
|
307 |
+
|
308 |
+
return $endpoints;
|
309 |
+
}
|
310 |
+
|
311 |
+
/**
|
312 |
+
* Match the request to a callback and call it
|
313 |
+
*
|
314 |
+
* @since 2.1
|
315 |
+
* @return mixed The value returned by the callback, or a WP_Error instance
|
316 |
+
*/
|
317 |
+
public function dispatch() {
|
318 |
+
switch ( $this->method ) {
|
319 |
+
|
320 |
+
case 'HEAD':
|
321 |
+
case 'GET':
|
322 |
+
$method = self::METHOD_GET;
|
323 |
+
break;
|
324 |
+
case 'POST':
|
325 |
+
$method = self::METHOD_POST;
|
326 |
+
break;
|
327 |
+
case 'PUT':
|
328 |
+
$method = self::METHOD_PUT;
|
329 |
+
break;
|
330 |
+
case 'PATCH':
|
331 |
+
$method = self::METHOD_PATCH;
|
332 |
+
break;
|
333 |
+
case 'DELETE':
|
334 |
+
$method = self::METHOD_DELETE;
|
335 |
+
break;
|
336 |
+
|
337 |
+
default:
|
338 |
+
return new WP_Error( 'aftership_api_unsupported_method', __( 'Unsupported request method', 'aftership' ), array( 'status' => 400 ) );
|
339 |
+
}
|
340 |
+
|
341 |
+
foreach ( $this->get_routes() as $route => $handlers ) {
|
342 |
+
foreach ( $handlers as $handler ) {
|
343 |
+
$callback = $handler[0];
|
344 |
+
$supported = isset( $handler[1] ) ? $handler[1] : self::METHOD_GET;
|
345 |
+
|
346 |
+
if ( ! ( $supported & $method ) ) {
|
347 |
+
continue;
|
348 |
+
}
|
349 |
+
|
350 |
+
$match = preg_match( '@^' . $route . '$@i', urldecode( $this->path ), $args );
|
351 |
+
|
352 |
+
if ( ! $match ) {
|
353 |
+
continue;
|
354 |
+
}
|
355 |
+
|
356 |
+
if ( ! is_callable( $callback ) ) {
|
357 |
+
return new WP_Error( 'aftership_api_invalid_handler', __( 'The handler for the route is invalid', 'aftership' ), array( 'status' => 500 ) );
|
358 |
+
}
|
359 |
+
|
360 |
+
$args = array_merge( $args, $this->params['GET'] );
|
361 |
+
if ( $method & self::METHOD_POST ) {
|
362 |
+
$args = array_merge( $args, $this->params['POST'] );
|
363 |
+
}
|
364 |
+
if ( $supported & self::ACCEPT_DATA ) {
|
365 |
+
$data = $this->handler->parse_body( $this->get_raw_data() );
|
366 |
+
$args = array_merge( $args, array( 'data' => $data ) );
|
367 |
+
} elseif ( $supported & self::ACCEPT_RAW_DATA ) {
|
368 |
+
$data = $this->get_raw_data();
|
369 |
+
$args = array_merge( $args, array( 'data' => $data ) );
|
370 |
+
}
|
371 |
+
|
372 |
+
$args['_method'] = $method;
|
373 |
+
$args['_route'] = $route;
|
374 |
+
$args['_path'] = $this->path;
|
375 |
+
$args['_headers'] = $this->headers;
|
376 |
+
$args['_files'] = $this->files;
|
377 |
+
|
378 |
+
$args = apply_filters( 'aftership_api_dispatch_args', $args, $callback );
|
379 |
+
|
380 |
+
// Allow plugins to halt the request via this filter
|
381 |
+
if ( is_wp_error( $args ) ) {
|
382 |
+
return $args;
|
383 |
+
}
|
384 |
+
|
385 |
+
$params = $this->sort_callback_params( $callback, $args );
|
386 |
+
if ( is_wp_error( $params ) ) {
|
387 |
+
return $params;
|
388 |
+
}
|
389 |
+
|
390 |
+
return call_user_func_array( $callback, $params );
|
391 |
+
}
|
392 |
+
}
|
393 |
+
|
394 |
+
return new WP_Error( 'aftership_api_no_route', __( 'No route was found matching the URL and request method', 'aftership' ), array( 'status' => 404 ) );
|
395 |
+
}
|
396 |
+
|
397 |
+
/**
|
398 |
+
* Sort parameters by order specified in method declaration
|
399 |
+
*
|
400 |
+
* Takes a callback and a list of available params, then filters and sorts
|
401 |
+
* by the parameters the method actually needs, using the Reflection API
|
402 |
+
*
|
403 |
+
* @since 2.1
|
404 |
+
* @param callable|array $callback the endpoint callback
|
405 |
+
* @param array $provided the provided request parameters
|
406 |
+
* @return array
|
407 |
+
*/
|
408 |
+
protected function sort_callback_params( $callback, $provided ) {
|
409 |
+
if ( is_array( $callback ) ) {
|
410 |
+
$ref_func = new ReflectionMethod( $callback[0], $callback[1] );
|
411 |
+
} else {
|
412 |
+
$ref_func = new ReflectionFunction( $callback );
|
413 |
+
}
|
414 |
+
|
415 |
+
$wanted = $ref_func->getParameters();
|
416 |
+
$ordered_parameters = array();
|
417 |
+
|
418 |
+
foreach ( $wanted as $param ) {
|
419 |
+
if ( isset( $provided[ $param->getName() ] ) ) {
|
420 |
+
// We have this parameters in the list to choose from
|
421 |
+
|
422 |
+
$ordered_parameters[] = is_array( $provided[ $param->getName() ] ) ? array_map( 'urldecode', $provided[ $param->getName() ] ) : urldecode( $provided[ $param->getName() ] );
|
423 |
+
} elseif ( $param->isDefaultValueAvailable() ) {
|
424 |
+
// We don't have this parameter, but it's optional
|
425 |
+
$ordered_parameters[] = $param->getDefaultValue();
|
426 |
+
} else {
|
427 |
+
// We don't have this parameter and it wasn't optional, abort!
|
428 |
+
return new WP_Error( 'aftership_api_missing_callback_param', sprintf( __( 'Missing parameter %s', 'aftership' ), $param->getName() ), array( 'status' => 400 ) );
|
429 |
+
}
|
430 |
+
}
|
431 |
+
return $ordered_parameters;
|
432 |
+
}
|
433 |
+
|
434 |
+
/**
|
435 |
+
* Get the site index.
|
436 |
+
*
|
437 |
+
* This endpoint describes the capabilities of the site.
|
438 |
+
*
|
439 |
+
* @since 2.1
|
440 |
+
* @return array Index entity
|
441 |
+
*/
|
442 |
+
public function get_index() {
|
443 |
+
// General site data
|
444 |
+
$available = array(
|
445 |
+
'store' => array(
|
446 |
+
'name' => get_option( 'blogname' ),
|
447 |
+
'description' => get_option( 'blogdescription' ),
|
448 |
+
'URL' => get_option( 'siteurl' ),
|
449 |
+
'wc_version' => WC()->version,
|
450 |
+
'latest_api_version' => AFTERSHIP_LATEST_API_VERSION,
|
451 |
+
'routes' => array(),
|
452 |
+
'meta' => array(
|
453 |
+
'timezone' => wc_timezone_string(),
|
454 |
+
'currency' => get_woocommerce_currency(),
|
455 |
+
'currency_format' => get_woocommerce_currency_symbol(),
|
456 |
+
'tax_included' => ( 'yes' === get_option( 'aftership_prices_include_tax' ) ),
|
457 |
+
'weight_unit' => get_option( 'aftership_weight_unit' ),
|
458 |
+
'dimension_unit' => get_option( 'aftership_dimension_unit' ),
|
459 |
+
'ssl_enabled' => ( 'yes' === get_option( 'aftership_force_ssl_checkout' ) ),
|
460 |
+
'permalinks_enabled' => ( '' !== get_option( 'permalink_structure' ) ),
|
461 |
+
'links' => array(
|
462 |
+
'help' => 'https://aftership.uservoice.com/knowledgebase',
|
463 |
+
),
|
464 |
+
),
|
465 |
+
),
|
466 |
+
);
|
467 |
+
|
468 |
+
// Find the available routes
|
469 |
+
foreach ( $this->get_routes() as $route => $callbacks ) {
|
470 |
+
$data = array();
|
471 |
+
|
472 |
+
$route = preg_replace( '#\(\?P(<\w+?>).*?\)#', '$1', $route );
|
473 |
+
$methods = array();
|
474 |
+
foreach ( self::$method_map as $name => $bitmask ) {
|
475 |
+
foreach ( $callbacks as $callback ) {
|
476 |
+
// Skip to the next route if any callback is hidden
|
477 |
+
if ( $callback[1] & self::HIDDEN_ENDPOINT ) {
|
478 |
+
continue 3;
|
479 |
+
}
|
480 |
+
|
481 |
+
if ( $callback[1] & $bitmask ) {
|
482 |
+
$data['supports'][] = $name;
|
483 |
+
}
|
484 |
+
|
485 |
+
if ( $callback[1] & self::ACCEPT_DATA ) {
|
486 |
+
$data['accepts_data'] = true;
|
487 |
+
}
|
488 |
+
|
489 |
+
// For non-variable routes, generate links
|
490 |
+
if ( strpos( $route, '<' ) === false ) {
|
491 |
+
$data['meta'] = array(
|
492 |
+
'self' => $route,
|
493 |
+
);
|
494 |
+
}
|
495 |
+
}
|
496 |
+
}
|
497 |
+
$available['store']['routes'][ $route ] = apply_filters( 'aftership_api_endpoints_description', $data );
|
498 |
+
}
|
499 |
+
return apply_filters( 'aftership_api_index', $available );
|
500 |
+
}
|
501 |
+
|
502 |
+
/**
|
503 |
+
* Send a HTTP status code
|
504 |
+
*
|
505 |
+
* @since 2.1
|
506 |
+
* @param int $code HTTP status
|
507 |
+
*/
|
508 |
+
public function send_status( $code ) {
|
509 |
+
status_header( $code );
|
510 |
+
}
|
511 |
+
|
512 |
+
/**
|
513 |
+
* Send a HTTP header
|
514 |
+
*
|
515 |
+
* @since 2.1
|
516 |
+
* @param string $key Header key
|
517 |
+
* @param string $value Header value
|
518 |
+
* @param boolean $replace Should we replace the existing header?
|
519 |
+
*/
|
520 |
+
public function header( $key, $value, $replace = true ) {
|
521 |
+
header( sprintf( '%s: %s', $key, $value ), $replace );
|
522 |
+
}
|
523 |
+
|
524 |
+
/**
|
525 |
+
* Send a Link header
|
526 |
+
*
|
527 |
+
* @internal The $rel parameter is first, as this looks nicer when sending multiple
|
528 |
+
*
|
529 |
+
* @link http://tools.ietf.org/html/rfc5988
|
530 |
+
* @link http://www.iana.org/assignments/link-relations/link-relations.xml
|
531 |
+
*
|
532 |
+
* @since 2.1
|
533 |
+
* @param string $rel Link relation. Either a registered type, or an absolute URL
|
534 |
+
* @param string $link Target IRI for the link
|
535 |
+
* @param array $other Other parameters to send, as an associative array
|
536 |
+
*/
|
537 |
+
public function link_header( $rel, $link, $other = array() ) {
|
538 |
+
|
539 |
+
$header = sprintf( '<%s>; rel="%s"', $link, esc_attr( $rel ) );
|
540 |
+
|
541 |
+
foreach ( $other as $key => $value ) {
|
542 |
+
|
543 |
+
if ( 'title' == $key ) {
|
544 |
+
|
545 |
+
$value = '"' . $value . '"';
|
546 |
+
}
|
547 |
+
|
548 |
+
$header .= '; ' . $key . '=' . $value;
|
549 |
+
}
|
550 |
+
|
551 |
+
$this->header( 'Link', $header, false );
|
552 |
+
}
|
553 |
+
|
554 |
+
/**
|
555 |
+
* Send pagination headers for resources
|
556 |
+
*
|
557 |
+
* @since 2.1
|
558 |
+
* @param WP_Query|WP_User_Query $query
|
559 |
+
*/
|
560 |
+
public function add_pagination_headers( $query ) {
|
561 |
+
|
562 |
+
// WP_User_Query
|
563 |
+
if ( is_a( $query, 'WP_User_Query' ) ) {
|
564 |
+
|
565 |
+
$page = $query->page;
|
566 |
+
$single = count( $query->get_results() ) > 1;
|
567 |
+
$total = $query->get_total();
|
568 |
+
$total_pages = $query->total_pages;
|
569 |
+
|
570 |
+
// WP_Query
|
571 |
+
} else {
|
572 |
+
|
573 |
+
$page = $query->get( 'paged' );
|
574 |
+
$single = $query->is_single();
|
575 |
+
$total = $query->found_posts;
|
576 |
+
$total_pages = $query->max_num_pages;
|
577 |
+
}
|
578 |
+
|
579 |
+
if ( ! $page ) {
|
580 |
+
$page = 1;
|
581 |
+
}
|
582 |
+
|
583 |
+
$next_page = absint( $page ) + 1;
|
584 |
+
|
585 |
+
if ( ! $single ) {
|
586 |
+
|
587 |
+
// first/prev
|
588 |
+
if ( $page > 1 ) {
|
589 |
+
$this->link_header( 'first', $this->get_paginated_url( 1 ) );
|
590 |
+
$this->link_header( 'prev', $this->get_paginated_url( $page - 1 ) );
|
591 |
+
}
|
592 |
+
|
593 |
+
// next
|
594 |
+
if ( $next_page <= $total_pages ) {
|
595 |
+
$this->link_header( 'next', $this->get_paginated_url( $next_page ) );
|
596 |
+
}
|
597 |
+
|
598 |
+
// last
|
599 |
+
if ( $page != $total_pages ) {
|
600 |
+
$this->link_header( 'last', $this->get_paginated_url( $total_pages ) );
|
601 |
+
}
|
602 |
+
}
|
603 |
+
|
604 |
+
$this->header( 'X-WC-Total', $total );
|
605 |
+
$this->header( 'X-WC-TotalPages', $total_pages );
|
606 |
+
|
607 |
+
do_action( 'aftership_api_pagination_headers', $this, $query );
|
608 |
+
}
|
609 |
+
|
610 |
+
/**
|
611 |
+
* Returns the request URL with the page query parameter set to the specified page
|
612 |
+
*
|
613 |
+
* @since 2.1
|
614 |
+
* @param int $page
|
615 |
+
* @return string
|
616 |
+
*/
|
617 |
+
private function get_paginated_url( $page ) {
|
618 |
+
|
619 |
+
// remove existing page query param
|
620 |
+
$request = remove_query_arg( 'page' );
|
621 |
+
|
622 |
+
// add provided page query param
|
623 |
+
$request = urldecode( add_query_arg( 'page', $page, $request ) );
|
624 |
+
|
625 |
+
// get the home host
|
626 |
+
$host = parse_url( get_home_url(), PHP_URL_HOST );
|
627 |
+
|
628 |
+
return set_url_scheme( "http://{$host}{$request}" );
|
629 |
+
}
|
630 |
+
|
631 |
+
/**
|
632 |
+
* Retrieve the raw request entity (body)
|
633 |
+
*
|
634 |
+
* @since 2.1
|
635 |
+
* @return string
|
636 |
+
*/
|
637 |
+
public function get_raw_data() {
|
638 |
+
return file_get_contents( 'php://input' );
|
639 |
+
}
|
640 |
+
|
641 |
+
/**
|
642 |
+
* Parse an RFC3339 datetime into a MySQl datetime
|
643 |
+
*
|
644 |
+
* Invalid dates default to unix epoch
|
645 |
+
*
|
646 |
+
* @since 2.1
|
647 |
+
* @param string $datetime RFC3339 datetime
|
648 |
+
* @return string MySQl datetime (YYYY-MM-DD HH:MM:SS)
|
649 |
+
*/
|
650 |
+
public function parse_datetime( $datetime ) {
|
651 |
+
|
652 |
+
// Strip millisecond precision (a full stop followed by one or more digits)
|
653 |
+
if ( strpos( $datetime, '.' ) !== false ) {
|
654 |
+
$datetime = preg_replace( '/\.\d+/', '', $datetime );
|
655 |
+
}
|
656 |
+
|
657 |
+
// default timezone to UTC
|
658 |
+
$datetime = preg_replace( '/[+-]\d+:+\d+$/', '+00:00', $datetime );
|
659 |
+
|
660 |
+
try {
|
661 |
+
|
662 |
+
$datetime = new DateTime( $datetime, new DateTimeZone( 'UTC' ) );
|
663 |
+
|
664 |
+
} catch ( Exception $e ) {
|
665 |
+
|
666 |
+
$datetime = new DateTime( '@0' );
|
667 |
+
|
668 |
+
}
|
669 |
+
|
670 |
+
return $datetime->format( 'Y-m-d H:i:s' );
|
671 |
+
}
|
672 |
+
|
673 |
+
/**
|
674 |
+
* Format a unix timestamp or MySQL datetime into an RFC3339 datetime
|
675 |
+
*
|
676 |
+
* @since 2.1
|
677 |
+
* @param int|string $timestamp unix timestamp or MySQL datetime
|
678 |
+
* @param bool $convert_to_utc
|
679 |
+
* @return string RFC3339 datetime
|
680 |
+
*/
|
681 |
+
public function format_datetime( $timestamp, $convert_to_utc = false ) {
|
682 |
+
|
683 |
+
if ( $convert_to_utc ) {
|
684 |
+
$timezone = new DateTimeZone( wc_timezone_string() );
|
685 |
+
} else {
|
686 |
+
$timezone = new DateTimeZone( 'UTC' );
|
687 |
+
}
|
688 |
+
|
689 |
+
try {
|
690 |
+
|
691 |
+
if ( is_numeric( $timestamp ) ) {
|
692 |
+
$date = new DateTime( "@{$timestamp}" );
|
693 |
+
} else {
|
694 |
+
$date = new DateTime( $timestamp, $timezone );
|
695 |
+
}
|
696 |
+
|
697 |
+
// convert to UTC by adjusting the time based on the offset of the site's timezone
|
698 |
+
if ( $convert_to_utc ) {
|
699 |
+
$date->modify( -1 * $date->getOffset() . ' seconds' );
|
700 |
+
}
|
701 |
+
} catch ( Exception $e ) {
|
702 |
+
|
703 |
+
$date = new DateTime( '@0' );
|
704 |
+
}
|
705 |
+
|
706 |
+
return $date->format( 'Y-m-d\TH:i:s\Z' );
|
707 |
+
}
|
708 |
+
|
709 |
+
/**
|
710 |
+
* Extract headers from a PHP-style $_SERVER array
|
711 |
+
*
|
712 |
+
* @since 2.1
|
713 |
+
* @param array $server Associative array similar to $_SERVER
|
714 |
+
* @return array Headers extracted from the input
|
715 |
+
*/
|
716 |
+
public function get_headers( $server ) {
|
717 |
+
$headers = array();
|
718 |
+
// CONTENT_* headers are not prefixed with HTTP_
|
719 |
+
$additional = array(
|
720 |
+
'CONTENT_LENGTH' => true,
|
721 |
+
'CONTENT_MD5' => true,
|
722 |
+
'CONTENT_TYPE' => true,
|
723 |
+
);
|
724 |
+
|
725 |
+
foreach ( $server as $key => $value ) {
|
726 |
+
if ( strpos( $key, 'HTTP_' ) === 0 ) {
|
727 |
+
$headers[ substr( $key, 5 ) ] = $value;
|
728 |
+
} elseif ( isset( $additional[ $key ] ) ) {
|
729 |
+
$headers[ $key ] = $value;
|
730 |
+
}
|
731 |
+
}
|
732 |
+
|
733 |
+
return $headers;
|
734 |
+
}
|
735 |
+
|
736 |
+
/**
|
737 |
+
* Check if the current request accepts a JSON response by checking the endpoint suffix (.json) or
|
738 |
+
* the HTTP ACCEPT header
|
739 |
+
*
|
740 |
+
* @since 2.1
|
741 |
+
* @return bool
|
742 |
+
*/
|
743 |
+
private function is_json_request() {
|
744 |
+
// check path
|
745 |
+
if ( false !== stripos( $this->path, '.json' ) ) {
|
746 |
+
return true;
|
747 |
+
}
|
748 |
+
|
749 |
+
// check ACCEPT header, only 'application/json' is acceptable, see RFC 4627
|
750 |
+
if ( isset( $this->headers['ACCEPT'] ) && 'application/json' == $this->headers['ACCEPT'] ) {
|
751 |
+
return true;
|
752 |
+
}
|
753 |
+
|
754 |
+
return false;
|
755 |
+
}
|
756 |
+
|
757 |
+
/**
|
758 |
+
* Check if the current request accepts an XML response by checking the endpoint suffix (.xml) or
|
759 |
+
* the HTTP ACCEPT header
|
760 |
+
*
|
761 |
+
* @since 2.1
|
762 |
+
* @return bool
|
763 |
+
*/
|
764 |
+
private function is_xml_request() {
|
765 |
+
// check path
|
766 |
+
if ( false !== stripos( $this->path, '.xml' ) ) {
|
767 |
+
return true;
|
768 |
+
}
|
769 |
+
|
770 |
+
// check headers, 'application/xml' or 'text/xml' are acceptable, see RFC 2376
|
771 |
+
if ( isset( $this->headers['ACCEPT'] ) && ( 'application/xml' == $this->headers['ACCEPT'] || 'text/xml' == $this->headers['ACCEPT'] ) ) {
|
772 |
+
return true;
|
773 |
+
}
|
774 |
+
|
775 |
+
return false;
|
776 |
+
}
|
777 |
+
|
778 |
+
/**
|
779 |
+
* Converts the WooCommerce country codes to 3-letter ISO codes
|
780 |
+
* https://en.wikipedia.org/wiki/ISO_3166-1_alpha-3
|
781 |
+
*
|
782 |
+
* @param string WooCommerce's 2 letter country code
|
783 |
+
* @return string ISO 3-letter country code
|
784 |
+
*/
|
785 |
+
public function convert_country_code( $country ) {
|
786 |
+
$countries = array(
|
787 |
+
'AF' => 'AFG', // Afghanistan
|
788 |
+
'AX' => 'ALA', // Åland Islands
|
789 |
+
'AL' => 'ALB', // Albania
|
790 |
+
'DZ' => 'DZA', // Algeria
|
791 |
+
'AS' => 'ASM', // American Samoa
|
792 |
+
'AD' => 'AND', // Andorra
|
793 |
+
'AO' => 'AGO', // Angola
|
794 |
+
'AI' => 'AIA', // Anguilla
|
795 |
+
'AQ' => 'ATA', // Antarctica
|
796 |
+
'AG' => 'ATG', // Antigua and Barbuda
|
797 |
+
'AR' => 'ARG', // Argentina
|
798 |
+
'AM' => 'ARM', // Armenia
|
799 |
+
'AW' => 'ABW', // Aruba
|
800 |
+
'AU' => 'AUS', // Australia
|
801 |
+
'AT' => 'AUT', // Austria
|
802 |
+
'AZ' => 'AZE', // Azerbaijan
|
803 |
+
'BS' => 'BHS', // Bahamas
|
804 |
+
'BH' => 'BHR', // Bahrain
|
805 |
+
'BD' => 'BGD', // Bangladesh
|
806 |
+
'BB' => 'BRB', // Barbados
|
807 |
+
'BY' => 'BLR', // Belarus
|
808 |
+
'BE' => 'BEL', // Belgium
|
809 |
+
'BZ' => 'BLZ', // Belize
|
810 |
+
'BJ' => 'BEN', // Benin
|
811 |
+
'BM' => 'BMU', // Bermuda
|
812 |
+
'BT' => 'BTN', // Bhutan
|
813 |
+
'BO' => 'BOL', // Bolivia
|
814 |
+
'BQ' => 'BES', // Bonaire, Saint Estatius and Saba
|
815 |
+
'BA' => 'BIH', // Bosnia and Herzegovina
|
816 |
+
'BW' => 'BWA', // Botswana
|
817 |
+
'BV' => 'BVT', // Bouvet Islands
|
818 |
+
'BR' => 'BRA', // Brazil
|
819 |
+
'IO' => 'IOT', // British Indian Ocean Territory
|
820 |
+
'BN' => 'BRN', // Brunei
|
821 |
+
'BG' => 'BGR', // Bulgaria
|
822 |
+
'BF' => 'BFA', // Burkina Faso
|
823 |
+
'BI' => 'BDI', // Burundi
|
824 |
+
'KH' => 'KHM', // Cambodia
|
825 |
+
'CM' => 'CMR', // Cameroon
|
826 |
+
'CA' => 'CAN', // Canada
|
827 |
+
'CV' => 'CPV', // Cape Verde
|
828 |
+
'KY' => 'CYM', // Cayman Islands
|
829 |
+
'CF' => 'CAF', // Central African Republic
|
830 |
+
'TD' => 'TCD', // Chad
|
831 |
+
'CL' => 'CHL', // Chile
|
832 |
+
'CN' => 'CHN', // China
|
833 |
+
'CX' => 'CXR', // Christmas Island
|
834 |
+
'CC' => 'CCK', // Cocos (Keeling) Islands
|
835 |
+
'CO' => 'COL', // Colombia
|
836 |
+
'KM' => 'COM', // Comoros
|
837 |
+
'CG' => 'COG', // Congo
|
838 |
+
'CD' => 'COD', // Congo, Democratic Republic of the
|
839 |
+
'CK' => 'COK', // Cook Islands
|
840 |
+
'CR' => 'CRI', // Costa Rica
|
841 |
+
'CI' => 'CIV', // Côte d\'Ivoire
|
842 |
+
'HR' => 'HRV', // Croatia
|
843 |
+
'CU' => 'CUB', // Cuba
|
844 |
+
'CW' => 'CUW', // Curaçao
|
845 |
+
'CY' => 'CYP', // Cyprus
|
846 |
+
'CZ' => 'CZE', // Czech Republic
|
847 |
+
'DK' => 'DNK', // Denmark
|
848 |
+
'DJ' => 'DJI', // Djibouti
|
849 |
+
'DM' => 'DMA', // Dominica
|
850 |
+
'DO' => 'DOM', // Dominican Republic
|
851 |
+
'EC' => 'ECU', // Ecuador
|
852 |
+
'EG' => 'EGY', // Egypt
|
853 |
+
'SV' => 'SLV', // El Salvador
|
854 |
+
'GQ' => 'GNQ', // Equatorial Guinea
|
855 |
+
'ER' => 'ERI', // Eritrea
|
856 |
+
'EE' => 'EST', // Estonia
|
857 |
+
'ET' => 'ETH', // Ethiopia
|
858 |
+
'FK' => 'FLK', // Falkland Islands
|
859 |
+
'FO' => 'FRO', // Faroe Islands
|
860 |
+
'FJ' => 'FIJ', // Fiji
|
861 |
+
'FI' => 'FIN', // Finland
|
862 |
+
'FR' => 'FRA', // France
|
863 |
+
'GF' => 'GUF', // French Guiana
|
864 |
+
'PF' => 'PYF', // French Polynesia
|
865 |
+
'TF' => 'ATF', // French Southern Territories
|
866 |
+
'GA' => 'GAB', // Gabon
|
867 |
+
'GM' => 'GMB', // Gambia
|
868 |
+
'GE' => 'GEO', // Georgia
|
869 |
+
'DE' => 'DEU', // Germany
|
870 |
+
'GH' => 'GHA', // Ghana
|
871 |
+
'GI' => 'GIB', // Gibraltar
|
872 |
+
'GR' => 'GRC', // Greece
|
873 |
+
'GL' => 'GRL', // Greenland
|
874 |
+
'GD' => 'GRD', // Grenada
|
875 |
+
'GP' => 'GLP', // Guadeloupe
|
876 |
+
'GU' => 'GUM', // Guam
|
877 |
+
'GT' => 'GTM', // Guatemala
|
878 |
+
'GG' => 'GGY', // Guernsey
|
879 |
+
'GN' => 'GIN', // Guinea
|
880 |
+
'GW' => 'GNB', // Guinea-Bissau
|
881 |
+
'GY' => 'GUY', // Guyana
|
882 |
+
'HT' => 'HTI', // Haiti
|
883 |
+
'HM' => 'HMD', // Heard Island and McDonald Islands
|
884 |
+
'VA' => 'VAT', // Holy See (Vatican City State)
|
885 |
+
'HN' => 'HND', // Honduras
|
886 |
+
'HK' => 'HKG', // Hong Kong
|
887 |
+
'HU' => 'HUN', // Hungary
|
888 |
+
'IS' => 'ISL', // Iceland
|
889 |
+
'IN' => 'IND', // India
|
890 |
+
'ID' => 'IDN', // Indonesia
|
891 |
+
'IR' => 'IRN', // Iran
|
892 |
+
'IQ' => 'IRQ', // Iraq
|
893 |
+
'IE' => 'IRL', // Republic of Ireland
|
894 |
+
'IM' => 'IMN', // Isle of Man
|
895 |
+
'IL' => 'ISR', // Israel
|
896 |
+
'IT' => 'ITA', // Italy
|
897 |
+
'JM' => 'JAM', // Jamaica
|
898 |
+
'JP' => 'JPN', // Japan
|
899 |
+
'JE' => 'JEY', // Jersey
|
900 |
+
'JO' => 'JOR', // Jordan
|
901 |
+
'KZ' => 'KAZ', // Kazakhstan
|
902 |
+
'KE' => 'KEN', // Kenya
|
903 |
+
'KI' => 'KIR', // Kiribati
|
904 |
+
'KP' => 'PRK', // Korea, Democratic People\'s Republic of
|
905 |
+
'KR' => 'KOR', // Korea, Republic of (South)
|
906 |
+
'KW' => 'KWT', // Kuwait
|
907 |
+
'KG' => 'KGZ', // Kyrgyzstan
|
908 |
+
'LA' => 'LAO', // Laos
|
909 |
+
'LV' => 'LVA', // Latvia
|
910 |
+
'LB' => 'LBN', // Lebanon
|
911 |
+
'LS' => 'LSO', // Lesotho
|
912 |
+
'LR' => 'LBR', // Liberia
|
913 |
+
'LY' => 'LBY', // Libya
|
914 |
+
'LI' => 'LIE', // Liechtenstein
|
915 |
+
'LT' => 'LTU', // Lithuania
|
916 |
+
'LU' => 'LUX', // Luxembourg
|
917 |
+
'MO' => 'MAC', // Macao S.A.R., China
|
918 |
+
'MK' => 'MKD', // Macedonia
|
919 |
+
'MG' => 'MDG', // Madagascar
|
920 |
+
'MW' => 'MWI', // Malawi
|
921 |
+
'MY' => 'MYS', // Malaysia
|
922 |
+
'MV' => 'MDV', // Maldives
|
923 |
+
'ML' => 'MLI', // Mali
|
924 |
+
'MT' => 'MLT', // Malta
|
925 |
+
'MH' => 'MHL', // Marshall Islands
|
926 |
+
'MQ' => 'MTQ', // Martinique
|
927 |
+
'MR' => 'MRT', // Mauritania
|
928 |
+
'MU' => 'MUS', // Mauritius
|
929 |
+
'YT' => 'MYT', // Mayotte
|
930 |
+
'MX' => 'MEX', // Mexico
|
931 |
+
'FM' => 'FSM', // Micronesia
|
932 |
+
'MD' => 'MDA', // Moldova
|
933 |
+
'MC' => 'MCO', // Monaco
|
934 |
+
'MN' => 'MNG', // Mongolia
|
935 |
+
'ME' => 'MNE', // Montenegro
|
936 |
+
'MS' => 'MSR', // Montserrat
|
937 |
+
'MA' => 'MAR', // Morocco
|
938 |
+
'MZ' => 'MOZ', // Mozambique
|
939 |
+
'MM' => 'MMR', // Myanmar
|
940 |
+
'NA' => 'NAM', // Namibia
|
941 |
+
'NR' => 'NRU', // Nauru
|
942 |
+
'NP' => 'NPL', // Nepal
|
943 |
+
'NL' => 'NLD', // Netherlands
|
944 |
+
'AN' => 'ANT', // Netherlands Antilles
|
945 |
+
'NC' => 'NCL', // New Caledonia
|
946 |
+
'NZ' => 'NZL', // New Zealand
|
947 |
+
'NI' => 'NIC', // Nicaragua
|
948 |
+
'NE' => 'NER', // Niger
|
949 |
+
'NG' => 'NGA', // Nigeria
|
950 |
+
'NU' => 'NIU', // Niue
|
951 |
+
'NF' => 'NFK', // Norfolk Island
|
952 |
+
'MP' => 'MNP', // Northern Mariana Islands
|
953 |
+
'NO' => 'NOR', // Norway
|
954 |
+
'OM' => 'OMN', // Oman
|
955 |
+
'PK' => 'PAK', // Pakistan
|
956 |
+
'PW' => 'PLW', // Palau
|
957 |
+
'PS' => 'PSE', // Palestinian Territory
|
958 |
+
'PA' => 'PAN', // Panama
|
959 |
+
'PG' => 'PNG', // Papua New Guinea
|
960 |
+
'PY' => 'PRY', // Paraguay
|
961 |
+
'PE' => 'PER', // Peru
|
962 |
+
'PH' => 'PHL', // Philippines
|
963 |
+
'PN' => 'PCN', // Pitcairn
|
964 |
+
'PL' => 'POL', // Poland
|
965 |
+
'PT' => 'PRT', // Portugal
|
966 |
+
'PR' => 'PRI', // Puerto Rico
|
967 |
+
'QA' => 'QAT', // Qatar
|
968 |
+
'RE' => 'REU', // Reunion
|
969 |
+
'RO' => 'ROU', // Romania
|
970 |
+
'RU' => 'RUS', // Russia
|
971 |
+
'RW' => 'RWA', // Rwanda
|
972 |
+
'BL' => 'BLM', // Saint Barthélemy
|
973 |
+
'SH' => 'SHN', // Saint Helena
|
974 |
+
'KN' => 'KNA', // Saint Kitts and Nevis
|
975 |
+
'LC' => 'LCA', // Saint Lucia
|
976 |
+
'MF' => 'MAF', // Saint Martin (French part)
|
977 |
+
'SX' => 'SXM', // Sint Maarten / Saint Matin (Dutch part)
|
978 |
+
'PM' => 'SPM', // Saint Pierre and Miquelon
|
979 |
+
'VC' => 'VCT', // Saint Vincent and the Grenadines
|
980 |
+
'WS' => 'WSM', // Samoa
|
981 |
+
'SM' => 'SMR', // San Marino
|
982 |
+
'ST' => 'STP', // São Tomé and Príncipe
|
983 |
+
'SA' => 'SAU', // Saudi Arabia
|
984 |
+
'SN' => 'SEN', // Senegal
|
985 |
+
'RS' => 'SRB', // Serbia
|
986 |
+
'SC' => 'SYC', // Seychelles
|
987 |
+
'SL' => 'SLE', // Sierra Leone
|
988 |
+
'SG' => 'SGP', // Singapore
|
989 |
+
'SK' => 'SVK', // Slovakia
|
990 |
+
'SI' => 'SVN', // Slovenia
|
991 |
+
'SB' => 'SLB', // Solomon Islands
|
992 |
+
'SO' => 'SOM', // Somalia
|
993 |
+
'ZA' => 'ZAF', // South Africa
|
994 |
+
'GS' => 'SGS', // South Georgia/Sandwich Islands
|
995 |
+
'SS' => 'SSD', // South Sudan
|
996 |
+
'ES' => 'ESP', // Spain
|
997 |
+
'LK' => 'LKA', // Sri Lanka
|
998 |
+
'SD' => 'SDN', // Sudan
|
999 |
+
'SR' => 'SUR', // Suriname
|
1000 |
+
'SJ' => 'SJM', // Svalbard and Jan Mayen
|
1001 |
+
'SZ' => 'SWZ', // Swaziland
|
1002 |
+
'SE' => 'SWE', // Sweden
|
1003 |
+
'CH' => 'CHE', // Switzerland
|
1004 |
+
'SY' => 'SYR', // Syria
|
1005 |
+
'TW' => 'TWN', // Taiwan
|
1006 |
+
'TJ' => 'TJK', // Tajikistan
|
1007 |
+
'TZ' => 'TZA', // Tanzania
|
1008 |
+
'TH' => 'THA', // Thailand
|
1009 |
+
'TL' => 'TLS', // Timor-Leste
|
1010 |
+
'TG' => 'TGO', // Togo
|
1011 |
+
'TK' => 'TKL', // Tokelau
|
1012 |
+
'TO' => 'TON', // Tonga
|
1013 |
+
'TT' => 'TTO', // Trinidad and Tobago
|
1014 |
+
'TN' => 'TUN', // Tunisia
|
1015 |
+
'TR' => 'TUR', // Turkey
|
1016 |
+
'TM' => 'TKM', // Turkmenistan
|
1017 |
+
'TC' => 'TCA', // Turks and Caicos Islands
|
1018 |
+
'TV' => 'TUV', // Tuvalu
|
1019 |
+
'UG' => 'UGA', // Uganda
|
1020 |
+
'UA' => 'UKR', // Ukraine
|
1021 |
+
'AE' => 'ARE', // United Arab Emirates
|
1022 |
+
'GB' => 'GBR', // United Kingdom
|
1023 |
+
'US' => 'USA', // United States
|
1024 |
+
'UM' => 'UMI', // United States Minor Outlying Islands
|
1025 |
+
'UY' => 'URY', // Uruguay
|
1026 |
+
'UZ' => 'UZB', // Uzbekistan
|
1027 |
+
'VU' => 'VUT', // Vanuatu
|
1028 |
+
'VE' => 'VEN', // Venezuela
|
1029 |
+
'VN' => 'VNM', // Vietnam
|
1030 |
+
'VG' => 'VGB', // Virgin Islands, British
|
1031 |
+
'VI' => 'VIR', // Virgin Island, U.S.
|
1032 |
+
'WF' => 'WLF', // Wallis and Futuna
|
1033 |
+
'EH' => 'ESH', // Western Sahara
|
1034 |
+
'YE' => 'YEM', // Yemen
|
1035 |
+
'ZM' => 'ZMB', // Zambia
|
1036 |
+
'ZW' => 'ZWE', // Zimbabwe
|
1037 |
+
);
|
1038 |
+
$iso_code = isset( $countries[ $country ] ) ? $countries[ $country ] : $country;
|
1039 |
+
return $iso_code;
|
1040 |
+
}
|
1041 |
+
}
|
includes/api/class-aftership-api.php
ADDED
@@ -0,0 +1,191 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* AfterShip API
|
4 |
+
*
|
5 |
+
* Handles AfterShip-API endpoint requests
|
6 |
+
*
|
7 |
+
* @author AfterShip
|
8 |
+
* @category API
|
9 |
+
* @package AfterShip
|
10 |
+
* @since 1.0
|
11 |
+
*/
|
12 |
+
|
13 |
+
if ( ! defined( 'ABSPATH' ) ) {
|
14 |
+
exit; // Exit if accessed directly
|
15 |
+
}
|
16 |
+
|
17 |
+
define( 'AFTERSHIP_LATEST_API_VERSION', 'v4' );
|
18 |
+
|
19 |
+
class AfterShip_API {
|
20 |
+
|
21 |
+
|
22 |
+
/** This is the major version for the REST API and takes
|
23 |
+
* first-order position in endpoint URLs
|
24 |
+
*/
|
25 |
+
const VERSION = 1;
|
26 |
+
|
27 |
+
/** @var WC_API_Server the REST API server */
|
28 |
+
public $server;
|
29 |
+
|
30 |
+
/**
|
31 |
+
* Setup class
|
32 |
+
*
|
33 |
+
* @access public
|
34 |
+
* @since 2.0
|
35 |
+
*/
|
36 |
+
public function __construct() {
|
37 |
+
// disable notice output in api json response.
|
38 |
+
error_reporting( 0 );
|
39 |
+
|
40 |
+
// add query vars.
|
41 |
+
add_filter( 'query_vars', array( $this, 'add_query_vars' ), 0 );
|
42 |
+
|
43 |
+
// register API endpoints.
|
44 |
+
add_action( 'init', array( $this, 'add_endpoint' ), 0 );
|
45 |
+
|
46 |
+
// handle REST/legacy API request.
|
47 |
+
add_action( 'parse_request', array( $this, 'handle_api_requests' ), 0 );
|
48 |
+
}
|
49 |
+
|
50 |
+
/**
|
51 |
+
* add_query_vars function.
|
52 |
+
*
|
53 |
+
* @access public
|
54 |
+
* @since 2.0
|
55 |
+
* @param $vars
|
56 |
+
* @return array
|
57 |
+
*/
|
58 |
+
public function add_query_vars( $vars ) {
|
59 |
+
$vars[] = 'aftership-api';
|
60 |
+
$vars[] = 'aftership-api-route';
|
61 |
+
return $vars;
|
62 |
+
}
|
63 |
+
|
64 |
+
/**
|
65 |
+
* add_endpoint function.
|
66 |
+
*
|
67 |
+
* @access public
|
68 |
+
* @since 2.0
|
69 |
+
* @return void
|
70 |
+
*/
|
71 |
+
public function add_endpoint() {
|
72 |
+
// REST API
|
73 |
+
add_rewrite_rule( '^aftership-api\/v' . self::VERSION . '/?$', 'index.php?aftership-api-route=/', 'top' );
|
74 |
+
add_rewrite_rule( '^aftership-api\/v' . self::VERSION . '(.*)?', 'index.php?aftership-api-route=$matches[1]', 'top' );
|
75 |
+
|
76 |
+
// legacy API for payment gateway IPNs
|
77 |
+
add_rewrite_endpoint( 'aftership-api', EP_ALL );
|
78 |
+
}
|
79 |
+
|
80 |
+
|
81 |
+
/**
|
82 |
+
* API request - Trigger any API requests
|
83 |
+
*
|
84 |
+
* @access public
|
85 |
+
* @since 2.0
|
86 |
+
* @return void
|
87 |
+
*/
|
88 |
+
public function handle_api_requests() {
|
89 |
+
global $wp;
|
90 |
+
|
91 |
+
if ( ! empty( $_GET['aftership-api'] ) ) {
|
92 |
+
$wp->query_vars['aftership-api'] = $_GET['aftership-api'];
|
93 |
+
}
|
94 |
+
|
95 |
+
if ( ! empty( $_GET['aftership-api-route'] ) ) {
|
96 |
+
$wp->query_vars['aftership-api-route'] = $_GET['aftership-api-route'];
|
97 |
+
}
|
98 |
+
|
99 |
+
// REST API request
|
100 |
+
if ( ! empty( $wp->query_vars['aftership-api-route'] ) ) {
|
101 |
+
|
102 |
+
define( 'AFTERSHIP_API_REQUEST', true );
|
103 |
+
|
104 |
+
// load required files
|
105 |
+
$this->includes();
|
106 |
+
|
107 |
+
$this->server = new AfterShip_API_Server( $wp->query_vars['aftership-api-route'] );
|
108 |
+
|
109 |
+
// load API resource classes
|
110 |
+
$this->register_resources( $this->server );
|
111 |
+
|
112 |
+
// Fire off the request
|
113 |
+
$this->server->serve_request();
|
114 |
+
|
115 |
+
exit;
|
116 |
+
}
|
117 |
+
|
118 |
+
// legacy API requests
|
119 |
+
if ( ! empty( $wp->query_vars['aftership-api'] ) ) {
|
120 |
+
|
121 |
+
// Buffer, we won't want any output here
|
122 |
+
ob_start();
|
123 |
+
|
124 |
+
// Get API trigger
|
125 |
+
$api = strtolower( esc_attr( $wp->query_vars['aftership-api'] ) );
|
126 |
+
|
127 |
+
// Load class if exists
|
128 |
+
if ( class_exists( $api ) ) {
|
129 |
+
$api_class = new $api();
|
130 |
+
}
|
131 |
+
|
132 |
+
// Trigger actions
|
133 |
+
do_action( 'woocommerce_api_' . $api );
|
134 |
+
|
135 |
+
// Done, clear buffer and exit
|
136 |
+
ob_end_clean();
|
137 |
+
die( '1' );
|
138 |
+
}
|
139 |
+
}
|
140 |
+
|
141 |
+
|
142 |
+
/**
|
143 |
+
* Include required files for REST API request
|
144 |
+
*
|
145 |
+
* @since 2.1
|
146 |
+
*/
|
147 |
+
private function includes() {
|
148 |
+
// API server / response handlers.
|
149 |
+
include_once( 'class-aftership-api-server.php' );
|
150 |
+
include_once( 'interface-aftership-api-handler.php' );
|
151 |
+
include_once( 'class-aftership-api-json-handler.php' );
|
152 |
+
include_once( 'class-aftership-api-common-json-handler.php' );
|
153 |
+
|
154 |
+
// authentication.
|
155 |
+
include_once( 'class-aftership-api-authentication.php' );
|
156 |
+
$this->authentication = new AfterShip_API_Authentication();
|
157 |
+
|
158 |
+
include_once( 'class-aftership-api-resource.php' );
|
159 |
+
|
160 |
+
// self api.
|
161 |
+
include_once( 'class-aftership-api-orders.php' );
|
162 |
+
include_once( 'v3/class-aftership-api-orders.php' );
|
163 |
+
include_once( 'v4/class-aftership-api-orders.php' );
|
164 |
+
include_once( 'v4/class-aftership-api-settings.php' );
|
165 |
+
|
166 |
+
}
|
167 |
+
|
168 |
+
/**
|
169 |
+
* Register available API resources
|
170 |
+
*
|
171 |
+
* @since 2.1
|
172 |
+
* @param object $server the REST server.
|
173 |
+
*/
|
174 |
+
public function register_resources( $server ) {
|
175 |
+
|
176 |
+
$api_classes = apply_filters(
|
177 |
+
'aftership_api_classes',
|
178 |
+
array(
|
179 |
+
'AfterShip_API_Orders',
|
180 |
+
'AfterShip_API_V3_Orders',
|
181 |
+
'AfterShip_API_V4_Orders',
|
182 |
+
'AfterShip_API_V4_Settings',
|
183 |
+
)
|
184 |
+
);
|
185 |
+
|
186 |
+
foreach ( $api_classes as $api_class ) {
|
187 |
+
$this->$api_class = new $api_class( $server );
|
188 |
+
}
|
189 |
+
}
|
190 |
+
|
191 |
+
}
|
{api → includes/api}/interface-aftership-api-handler.php
RENAMED
@@ -10,10 +10,12 @@
|
|
10 |
* @since 1.0
|
11 |
*/
|
12 |
|
13 |
-
if (!defined('ABSPATH'))
|
|
|
|
|
|
|
|
|
14 |
|
15 |
-
interface AfterShip_API_Handler
|
16 |
-
{
|
17 |
|
18 |
/**
|
19 |
* Get the content type for the response
|
@@ -32,7 +34,7 @@ interface AfterShip_API_Handler
|
|
32 |
* @param string $data
|
33 |
* @return array
|
34 |
*/
|
35 |
-
public function parse_body($data);
|
36 |
|
37 |
/**
|
38 |
* Generate a response from an array of data
|
@@ -41,6 +43,6 @@ interface AfterShip_API_Handler
|
|
41 |
* @param array $data
|
42 |
* @return string
|
43 |
*/
|
44 |
-
public function generate_response($data);
|
45 |
|
46 |
}
|
10 |
* @since 1.0
|
11 |
*/
|
12 |
|
13 |
+
if ( ! defined( 'ABSPATH' ) ) {
|
14 |
+
exit; // Exit if accessed directly
|
15 |
+
}
|
16 |
+
|
17 |
+
interface AfterShip_API_Handler {
|
18 |
|
|
|
|
|
19 |
|
20 |
/**
|
21 |
* Get the content type for the response
|
34 |
* @param string $data
|
35 |
* @return array
|
36 |
*/
|
37 |
+
public function parse_body( $data);
|
38 |
|
39 |
/**
|
40 |
* Generate a response from an array of data
|
43 |
* @param array $data
|
44 |
* @return string
|
45 |
*/
|
46 |
+
public function generate_response( $data);
|
47 |
|
48 |
}
|
includes/api/v3/class-aftership-api-orders.php
ADDED
@@ -0,0 +1,421 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* AfterShip API Orders Class
|
4 |
+
*
|
5 |
+
* Handles requests to the /orders endpoint
|
6 |
+
*
|
7 |
+
* @author AfterShip
|
8 |
+
* @category API
|
9 |
+
* @package AfterShip/API
|
10 |
+
* @since 1.0
|
11 |
+
*/
|
12 |
+
|
13 |
+
if ( ! defined( 'ABSPATH' ) ) {
|
14 |
+
exit;
|
15 |
+
} // Exit if accessed directly
|
16 |
+
|
17 |
+
class AfterShip_API_V3_Orders extends AfterShip_API_Resource {
|
18 |
+
|
19 |
+
|
20 |
+
/** @var string $base the route base */
|
21 |
+
protected $base = '/v3/orders';
|
22 |
+
|
23 |
+
/**
|
24 |
+
* Register the routes for this class
|
25 |
+
*
|
26 |
+
* GET /orders
|
27 |
+
*
|
28 |
+
* @param array $routes
|
29 |
+
*
|
30 |
+
* @return array
|
31 |
+
* @since 2.1
|
32 |
+
*/
|
33 |
+
public function register_routes( $routes ) {
|
34 |
+
// GET /orders/ping
|
35 |
+
$routes[ $this->base . '/ping' ] = array(
|
36 |
+
array( array( $this, 'ping' ), AfterShip_API_Server::READABLE ),
|
37 |
+
);
|
38 |
+
|
39 |
+
// GET /orders
|
40 |
+
$routes[ $this->base ] = array(
|
41 |
+
array( array( $this, 'get_orders' ), AfterShip_API_Server::READABLE ),
|
42 |
+
);
|
43 |
+
|
44 |
+
// GET /orders/:id
|
45 |
+
$routes[ $this->base . '/(?P<id>[\d]+)' ] = array(
|
46 |
+
array( array( $this, 'get_order' ), AfterShip_API_Server::READABLE ),
|
47 |
+
);
|
48 |
+
|
49 |
+
return $routes;
|
50 |
+
}
|
51 |
+
|
52 |
+
/**
|
53 |
+
* heath checkendpoint for WordPress url validation
|
54 |
+
*
|
55 |
+
* @return string
|
56 |
+
* @since 2.1
|
57 |
+
*/
|
58 |
+
public function ping() {
|
59 |
+
return 'pong';
|
60 |
+
}
|
61 |
+
|
62 |
+
/**
|
63 |
+
* Get orders
|
64 |
+
*
|
65 |
+
* @param string $updated_at_min
|
66 |
+
* @param string $updated_at_max
|
67 |
+
* @param string $max_results_number
|
68 |
+
*
|
69 |
+
* @return array
|
70 |
+
* @throws Exception
|
71 |
+
* @since 2.1
|
72 |
+
*/
|
73 |
+
public function get_orders( $fields = null, $filter = array(), $status = null, $page = 1 ) {
|
74 |
+
if ( ! empty( $status ) ) {
|
75 |
+
$filter['status'] = $status;
|
76 |
+
}
|
77 |
+
|
78 |
+
$filter['page'] = $page;
|
79 |
+
|
80 |
+
$query = $this->query_orders( $filter );
|
81 |
+
|
82 |
+
// define pagination
|
83 |
+
$pagination = array(
|
84 |
+
'page' => $query->query['paged'],
|
85 |
+
'limit' => intval( $query->query['posts_per_page'] ),
|
86 |
+
'total' => intval( $query->found_posts ),
|
87 |
+
);
|
88 |
+
|
89 |
+
$orders = array();
|
90 |
+
foreach ( $query->posts as $order_id ) {
|
91 |
+
if ( ! $this->is_readable( $order_id ) ) {
|
92 |
+
continue;
|
93 |
+
}
|
94 |
+
$orders[] = current( $this->get_order( $order_id, $fields ) );
|
95 |
+
}
|
96 |
+
|
97 |
+
return array(
|
98 |
+
'orders' => $orders,
|
99 |
+
'pagination' => $pagination,
|
100 |
+
);
|
101 |
+
}
|
102 |
+
|
103 |
+
/**
|
104 |
+
* get single order by id
|
105 |
+
*
|
106 |
+
* @param $id
|
107 |
+
* @return array|int|WP_Error
|
108 |
+
* @throws Exception
|
109 |
+
*/
|
110 |
+
public function get_order( $id, $fields = null ) {
|
111 |
+
$weight_unit = get_option( 'woocommerce_weight_unit' );
|
112 |
+
$dp = wc_get_price_decimals();
|
113 |
+
// ensure order ID is valid & user has permission to read
|
114 |
+
$id = $this->validate_request( $id, 'shop_order', 'read' );
|
115 |
+
if ( is_wp_error( $id ) ) {
|
116 |
+
return $id;
|
117 |
+
}
|
118 |
+
$order = new WC_Order( $id );
|
119 |
+
$customer = new WC_Customer( $order->get_customer_id() );
|
120 |
+
$current_shipping_method = current( $order->get_shipping_methods() );
|
121 |
+
$shipping_method = null;
|
122 |
+
if ( $current_shipping_method['method_id'] && $current_shipping_method['name'] ) {
|
123 |
+
$shipping_method = array(
|
124 |
+
'code' => $current_shipping_method['method_id'],
|
125 |
+
'name' => $current_shipping_method['name'],
|
126 |
+
);
|
127 |
+
}
|
128 |
+
$order_data = array(
|
129 |
+
'id' => (string) $order->get_id(),
|
130 |
+
'order_number' => (string) $order->get_order_number(),
|
131 |
+
'order_name' => '#' . (string) $order->get_order_number(),
|
132 |
+
'taxes_included' => ( $order->get_total_tax() > 0 ),
|
133 |
+
'shipping_method' => $shipping_method,
|
134 |
+
'order_total' => array(
|
135 |
+
'currency' => $order->get_currency(),
|
136 |
+
'amount' => (float) wc_format_decimal( $order->get_total(), 2 ),
|
137 |
+
),
|
138 |
+
'note' => $order->get_customer_note(),
|
139 |
+
'locale' => get_locale(),
|
140 |
+
'metrics' => array(
|
141 |
+
'placed_at' => $this->server->format_datetime( $order->get_date_created()->getTimestamp() ),
|
142 |
+
'updated_at' => $this->server->format_datetime( $order->get_date_modified()->getTimestamp() ),
|
143 |
+
'fully_shipped_at' => null,
|
144 |
+
'expected_earliest_delivery_at' => null,
|
145 |
+
'expected_last_delivery_at' => null,
|
146 |
+
),
|
147 |
+
'customer' => array(
|
148 |
+
'id' => (string) $order->get_customer_id(),
|
149 |
+
'first_name' => $customer->get_first_name(),
|
150 |
+
'last_name' => $customer->get_last_name(),
|
151 |
+
'emails' => ( $customer->get_email() ) ? array( $customer->get_email() ) : array(),
|
152 |
+
'phones' => ( $customer->get_billing_phone() ) ? array(
|
153 |
+
array(
|
154 |
+
'country_code' => null,
|
155 |
+
'number' => $customer->get_billing_phone(),
|
156 |
+
),
|
157 |
+
) : array(),
|
158 |
+
),
|
159 |
+
'shipping_address' => array(
|
160 |
+
'first_name' => $order->get_shipping_first_name(),
|
161 |
+
'last_name' => $order->get_shipping_last_name(),
|
162 |
+
'company' => $order->get_shipping_company(),
|
163 |
+
'address_line_1' => $order->get_shipping_address_1(),
|
164 |
+
'address_line_2' => $order->get_shipping_address_2(),
|
165 |
+
'city' => $order->get_shipping_city(),
|
166 |
+
'state' => $order->get_shipping_state(),
|
167 |
+
'country' => $this->server->convert_country_code( $order->get_shipping_country() ),
|
168 |
+
'postal_code' => $order->get_shipping_postcode(),
|
169 |
+
'email' => $order->get_billing_email(),
|
170 |
+
'phone' => array(
|
171 |
+
'country_code' => null,
|
172 |
+
'number' => $order->get_billing_phone(),
|
173 |
+
),
|
174 |
+
'address_type' => null,
|
175 |
+
'tax_number' => null,
|
176 |
+
),
|
177 |
+
'billing_address' => array(
|
178 |
+
'first_name' => $order->get_billing_first_name(),
|
179 |
+
'last_name' => $order->get_billing_last_name(),
|
180 |
+
'company' => $order->get_billing_company(),
|
181 |
+
'address_line_1' => $order->get_billing_address_1(),
|
182 |
+
'address_line_2' => $order->get_billing_address_2(),
|
183 |
+
'city' => $order->get_billing_city(),
|
184 |
+
'state' => $order->get_billing_state(),
|
185 |
+
'postal_code' => $order->get_billing_postcode(),
|
186 |
+
'country' => $this->server->convert_country_code( $order->get_billing_country() ),
|
187 |
+
'email' => $order->get_billing_email(),
|
188 |
+
'phone' => array(
|
189 |
+
'country_code' => null,
|
190 |
+
'number' => $order->get_billing_phone(),
|
191 |
+
),
|
192 |
+
'address_type' => null,
|
193 |
+
'tax_number' => null,
|
194 |
+
),
|
195 |
+
'status' => $order->get_status(),
|
196 |
+
'items' => array(),
|
197 |
+
'trackings' => array(),
|
198 |
+
);
|
199 |
+
|
200 |
+
// add line items
|
201 |
+
foreach ( $order->get_items() as $item_id => $item ) {
|
202 |
+
if ( is_callable( $item, 'get_product' ) ) {
|
203 |
+
$product = $item->get_product();
|
204 |
+
} else {
|
205 |
+
$product = $order->get_product_from_item( $item );
|
206 |
+
}
|
207 |
+
|
208 |
+
$product_id = 0;
|
209 |
+
$variation_id = 0;
|
210 |
+
$product_sku = null;
|
211 |
+
$weight = '';
|
212 |
+
$product_image_id = 0;
|
213 |
+
|
214 |
+
// Check if the product exists.
|
215 |
+
if ( is_object( $product ) ) {
|
216 |
+
$product_id = $item->get_product_id();
|
217 |
+
$variation_id = $item->get_variation_id();
|
218 |
+
$product_sku = $product->get_sku();
|
219 |
+
$weight = $product->get_weight();
|
220 |
+
$product_image_id = $product->get_image_id();
|
221 |
+
}
|
222 |
+
$subtotal = wc_format_decimal( $order->get_line_subtotal( $item, false, false ), $dp );
|
223 |
+
$total = wc_format_decimal( $order->get_line_total( $item, false, false ), $dp );
|
224 |
+
// set the response object
|
225 |
+
$terms_tags = get_the_terms( $product_id, 'product_tag' );
|
226 |
+
$product_tags = array();
|
227 |
+
foreach ( $terms_tags as $termsKey => $termsVal ) {
|
228 |
+
$product_tags[] = $termsVal->name;
|
229 |
+
}
|
230 |
+
$product_categories = array();
|
231 |
+
|
232 |
+
$categories = get_the_terms( $product_id, 'product_cat' );
|
233 |
+
foreach ( $categories as $categoriesKey => $categoriesVal ) {
|
234 |
+
$product_categories[] = $categoriesVal->name;
|
235 |
+
}
|
236 |
+
$order_data['items'][] = array(
|
237 |
+
'id' => (string) $item_id,
|
238 |
+
'product_id' => $product_id ? (string) $product_id : null,
|
239 |
+
'variant_id' => $variation_id ? (string) $variation_id : null,
|
240 |
+
'sku' => $product_sku,
|
241 |
+
'title' => $item['name'],
|
242 |
+
'quantity' => (int) $item['qty'],
|
243 |
+
'returnable_quantity' => (int) ( $item['qty'] - abs( $order->get_qty_refunded_for_item( $item_id ) ) ),
|
244 |
+
'unit_weight' => array(
|
245 |
+
'unit' => $weight_unit,
|
246 |
+
'value' => $weight === '' ? null : (float) $weight,
|
247 |
+
),
|
248 |
+
'unit_price' => array(
|
249 |
+
'currency' => $order->get_currency(),
|
250 |
+
'amount' => round( floatval( $subtotal ) / intval( $item['qty'] ), $dp ),
|
251 |
+
),
|
252 |
+
'discount' => array(
|
253 |
+
'currency' => $order->get_currency(),
|
254 |
+
'amount' => (float) ( $subtotal - $total ),
|
255 |
+
),
|
256 |
+
'image_urls' => $product_image_id && wp_get_attachment_url( $product_image_id ) ? array( wp_get_attachment_url( $product_image_id ) ) : array(),
|
257 |
+
'tags' => $product_tags,
|
258 |
+
'categories' => $product_categories,
|
259 |
+
);
|
260 |
+
}
|
261 |
+
|
262 |
+
$trackings = array();
|
263 |
+
// The function definition will be available after installing the aftership plugin.
|
264 |
+
if ( function_exists( 'order_post_meta_getter' ) ) {
|
265 |
+
$aftership_tracking_number = order_post_meta_getter( $order, 'aftership_tracking_number' );
|
266 |
+
if ( ! empty( $aftership_tracking_number ) ) {
|
267 |
+
$trackings[] = array(
|
268 |
+
'slug' => order_post_meta_getter( $order, 'aftership_tracking_provider' ),
|
269 |
+
'tracking_number' => $aftership_tracking_number,
|
270 |
+
'additional_fields' => array(
|
271 |
+
'account_number' => order_post_meta_getter( $order, 'aftership_tracking_account' ),
|
272 |
+
'key' => order_post_meta_getter( $order, 'aftership_tracking_key' ),
|
273 |
+
'postal_code' => order_post_meta_getter( $order, 'aftership_tracking_postal' ),
|
274 |
+
'ship_date' => order_post_meta_getter( $order, 'aftership_tracking_shipdate' ),
|
275 |
+
'destination_country' => order_post_meta_getter( $order, 'aftership_tracking_destination_country' ),
|
276 |
+
'state' => null,
|
277 |
+
'origin_country' => null,
|
278 |
+
),
|
279 |
+
);
|
280 |
+
}
|
281 |
+
|
282 |
+
// 兼容 woocommerce 官方的 tracking 插件
|
283 |
+
$woocommerce_tracking_arr = order_post_meta_getter( $order, 'wc_shipment_tracking_items' );
|
284 |
+
if ( empty( $aftership_tracking_number ) && ! empty( $woocommerce_tracking_arr ) ) {
|
285 |
+
foreach ( $woocommerce_tracking_arr as $trackingKey => $trackingVal ) {
|
286 |
+
$trackingInfo = $this->getTrackingInfoByShipmentTracking( $trackingVal );
|
287 |
+
$trackings[] = array(
|
288 |
+
'slug' => ! empty( $trackingInfo ) ? $trackingInfo['tracking_provider'] : $trackingVal['tracking_provider'],
|
289 |
+
'tracking_number' => $trackingVal['tracking_number'],
|
290 |
+
'additional_fields' => array(
|
291 |
+
'account_number' => null,
|
292 |
+
'key' => null,
|
293 |
+
'postal_code' => ! empty( $trackingInfo ) ? $trackingInfo['tracking_postal_code'] : null,
|
294 |
+
'ship_date' => null,
|
295 |
+
'destination_country' => null,
|
296 |
+
'state' => null,
|
297 |
+
'origin_country' => null,
|
298 |
+
),
|
299 |
+
);
|
300 |
+
}
|
301 |
+
}
|
302 |
+
$order_data['trackings'] = $trackings;
|
303 |
+
}
|
304 |
+
|
305 |
+
return array( 'order' => apply_filters( 'aftership_api_order_response', $order_data, $order, $fields, $this->server ) );
|
306 |
+
}
|
307 |
+
|
308 |
+
/**
|
309 |
+
* 从wc ShipmentTracking 插件获取 Postalcode - postnl
|
310 |
+
*
|
311 |
+
* @param $tracking_items
|
312 |
+
* @return array
|
313 |
+
*/
|
314 |
+
private function getTrackingInfoByShipmentTracking( $tracking_items ) {
|
315 |
+
if ( ! isset( $tracking_items['custom_tracking_link'] ) ) {
|
316 |
+
return array();
|
317 |
+
}
|
318 |
+
|
319 |
+
// 获取 postnl Postalcode
|
320 |
+
$urlArr = parse_url( stripslashes( $tracking_items['custom_tracking_link'] ) );
|
321 |
+
|
322 |
+
if ( $urlArr === false ) {
|
323 |
+
return array();
|
324 |
+
}
|
325 |
+
|
326 |
+
if ( ! isset( $urlArr['host'] ) ) {
|
327 |
+
return array();
|
328 |
+
}
|
329 |
+
|
330 |
+
$hostArr = explode( '.', $urlArr['host'] );
|
331 |
+
$hostArrIndex = count( $hostArr ) - 2;
|
332 |
+
if ( empty( $hostArr ) || ! isset( $hostArr[ $hostArrIndex ] ) ) {
|
333 |
+
return array();
|
334 |
+
}
|
335 |
+
|
336 |
+
if ( $hostArr[ $hostArrIndex ] == 'postnl' ) {
|
337 |
+
parse_str( $urlArr['query'], $queryArr );
|
338 |
+
if ( ! isset( $queryArr['Postalcode'] ) ) {
|
339 |
+
return array();
|
340 |
+
}
|
341 |
+
|
342 |
+
return array(
|
343 |
+
'tracking_provider' => 'postnl',
|
344 |
+
'tracking_postal_code' => str_replace( ' ', '', $queryArr['Postalcode'] ),
|
345 |
+
);
|
346 |
+
}
|
347 |
+
return array();
|
348 |
+
}
|
349 |
+
|
350 |
+
|
351 |
+
/**
|
352 |
+
* Helper method to get order post objects
|
353 |
+
*
|
354 |
+
* @param array $args request arguments for filtering query
|
355 |
+
*
|
356 |
+
* @return WP_Query
|
357 |
+
* @since 2.1
|
358 |
+
*/
|
359 |
+
private function query_orders( $args ) {
|
360 |
+
|
361 |
+
function aftership_wpbo_get_woo_version_number() {
|
362 |
+
// If get_plugins() isn't available, require it
|
363 |
+
if ( ! function_exists( 'get_plugins' ) ) {
|
364 |
+
require_once( ABSPATH . 'wp-admin/includes/plugin.php' );
|
365 |
+
}
|
366 |
+
|
367 |
+
// Create the plugins folder and file variables
|
368 |
+
$plugin_folder = get_plugins( '/' . 'woocommerce' );
|
369 |
+
$plugin_file = 'woocommerce.php';
|
370 |
+
|
371 |
+
// If the plugin version number is set, return it
|
372 |
+
if ( isset( $plugin_folder[ $plugin_file ]['Version'] ) ) {
|
373 |
+
return $plugin_folder[ $plugin_file ]['Version'];
|
374 |
+
|
375 |
+
} else {
|
376 |
+
// Otherwise return null
|
377 |
+
return null;
|
378 |
+
}
|
379 |
+
}
|
380 |
+
|
381 |
+
$woo_version = aftership_wpbo_get_woo_version_number();
|
382 |
+
|
383 |
+
if ( $woo_version >= 2.2 ) {
|
384 |
+
// set base query arguments
|
385 |
+
$query_args = array(
|
386 |
+
'fields' => 'ids',
|
387 |
+
'post_type' => 'shop_order',
|
388 |
+
// 'post_status' => 'publish',
|
389 |
+
'post_status' => array_keys( wc_get_order_statuses() ),
|
390 |
+
);
|
391 |
+
} else {
|
392 |
+
// set base query arguments
|
393 |
+
$query_args = array(
|
394 |
+
'fields' => 'ids',
|
395 |
+
'post_type' => 'shop_order',
|
396 |
+
'post_status' => 'publish',
|
397 |
+
);
|
398 |
+
}
|
399 |
+
|
400 |
+
// add status argument
|
401 |
+
if ( ! empty( $args['status'] ) ) {
|
402 |
+
|
403 |
+
$statuses = explode( ',', $args['status'] );
|
404 |
+
|
405 |
+
$query_args['tax_query'] = array(
|
406 |
+
array(
|
407 |
+
'taxonomy' => 'shop_order_status',
|
408 |
+
'field' => 'slug',
|
409 |
+
'terms' => $statuses,
|
410 |
+
),
|
411 |
+
);
|
412 |
+
|
413 |
+
unset( $args['status'] );
|
414 |
+
}
|
415 |
+
|
416 |
+
$query_args = $this->merge_query_args( $query_args, $args );
|
417 |
+
|
418 |
+
return new WP_Query( $query_args );
|
419 |
+
}
|
420 |
+
|
421 |
+
}
|
includes/api/v4/class-aftership-api-orders.php
ADDED
@@ -0,0 +1,441 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* AfterShip API Orders Class
|
4 |
+
*
|
5 |
+
* Handles requests to the /orders endpoint
|
6 |
+
*
|
7 |
+
* @author AfterShip
|
8 |
+
* @category API
|
9 |
+
* @package AfterShip/API
|
10 |
+
* @since 1.0
|
11 |
+
*/
|
12 |
+
|
13 |
+
if ( ! defined( 'ABSPATH' ) ) {
|
14 |
+
exit;
|
15 |
+
} // Exit if accessed directly
|
16 |
+
|
17 |
+
/***
|
18 |
+
* Class AfterShip_API_V4_Orders
|
19 |
+
*/
|
20 |
+
class AfterShip_API_V4_Orders extends AfterShip_API_V3_Orders {
|
21 |
+
|
22 |
+
|
23 |
+
/**
|
24 |
+
* Base router path.
|
25 |
+
*
|
26 |
+
* @var string $base base router path
|
27 |
+
*/
|
28 |
+
protected $base = '/v4/orders';
|
29 |
+
|
30 |
+
/**
|
31 |
+
* Register the routes for this class
|
32 |
+
*
|
33 |
+
* @param array $routes reg routers.
|
34 |
+
*
|
35 |
+
* @return array
|
36 |
+
*/
|
37 |
+
public function register_routes( $routes ) {
|
38 |
+
$routes[ $this->base . '/ping' ] = array(
|
39 |
+
array( array( $this, 'ping' ), AfterShip_API_Server::READABLE ),
|
40 |
+
);
|
41 |
+
|
42 |
+
$routes[ $this->base ] = array(
|
43 |
+
array( array( $this, 'get_orders' ), AfterShip_API_Server::READABLE ),
|
44 |
+
);
|
45 |
+
|
46 |
+
$routes[ $this->base . '/(?P<id>[\d]+)' ] = array(
|
47 |
+
array( array( $this, 'get_order' ), AfterShip_API_Server::READABLE ),
|
48 |
+
);
|
49 |
+
|
50 |
+
return $routes;
|
51 |
+
}
|
52 |
+
|
53 |
+
|
54 |
+
/**
|
55 |
+
* Get orders
|
56 |
+
*
|
57 |
+
* @param string $fields fields need for return.
|
58 |
+
* @param array $filter filter for query.
|
59 |
+
* @param string $status order status filter.
|
60 |
+
* @param int $page query pages.
|
61 |
+
*
|
62 |
+
* @return array
|
63 |
+
* @throws Exception May throw a exception.
|
64 |
+
*/
|
65 |
+
public function get_orders( $fields = null, $filter = array(), $status = null, $page = 1 ) {
|
66 |
+
if ( ! empty( $status ) ) {
|
67 |
+
$filter['status'] = $status;
|
68 |
+
}
|
69 |
+
|
70 |
+
$filter['page'] = $page;
|
71 |
+
|
72 |
+
$query = $this->query_orders( $filter );
|
73 |
+
|
74 |
+
$pagination = array(
|
75 |
+
'page' => $query->query['paged'],
|
76 |
+
'limit' => intval( $query->query['posts_per_page'] ),
|
77 |
+
'total' => intval( $query->found_posts ),
|
78 |
+
);
|
79 |
+
|
80 |
+
$orders = array();
|
81 |
+
foreach ( $query->posts as $order_id ) {
|
82 |
+
if ( ! $this->is_readable( $order_id ) ) {
|
83 |
+
continue;
|
84 |
+
}
|
85 |
+
$orders[] = $this->get_order( $order_id, $fields );
|
86 |
+
}
|
87 |
+
|
88 |
+
return array(
|
89 |
+
'orders' => $orders,
|
90 |
+
'pagination' => $pagination,
|
91 |
+
);
|
92 |
+
}
|
93 |
+
|
94 |
+
/**
|
95 |
+
* Get single order by id.
|
96 |
+
*
|
97 |
+
* @param int $id order id.
|
98 |
+
* @param string $fields order fields.
|
99 |
+
* @return array|int|WP_Error
|
100 |
+
* @throws Exception May throw a exception.
|
101 |
+
*/
|
102 |
+
public function get_order( $id, $fields = null ) {
|
103 |
+
$weight_unit = get_option( 'woocommerce_weight_unit' );
|
104 |
+
$dp = wc_get_price_decimals();
|
105 |
+
// ensure order ID is valid & user has permission to read.
|
106 |
+
$id = $this->validate_request( $id, 'shop_order', 'read' );
|
107 |
+
if ( is_wp_error( $id ) ) {
|
108 |
+
return $id;
|
109 |
+
}
|
110 |
+
$order = new WC_Order( $id );
|
111 |
+
$customer = new WC_Customer( $order->get_customer_id() );
|
112 |
+
$current_shipping_method = current( $order->get_shipping_methods() );
|
113 |
+
$shipping_method = null;
|
114 |
+
if ( $current_shipping_method['method_id'] && $current_shipping_method['name'] ) {
|
115 |
+
$shipping_method = array(
|
116 |
+
'code' => $current_shipping_method['method_id'],
|
117 |
+
'name' => $current_shipping_method['name'],
|
118 |
+
);
|
119 |
+
}
|
120 |
+
$order_data = array(
|
121 |
+
'id' => (string) $order->get_id(),
|
122 |
+
'order_number' => (string) $order->get_order_number(),
|
123 |
+
'order_name' => '#' . (string) $order->get_order_number(),
|
124 |
+
'taxes_included' => ( $order->get_total_tax() > 0 ),
|
125 |
+
'shipping_method' => $shipping_method,
|
126 |
+
'order_total' => array(
|
127 |
+
'currency' => $order->get_currency(),
|
128 |
+
'amount' => (float) wc_format_decimal( $order->get_total(), 2 ),
|
129 |
+
),
|
130 |
+
'note' => $order->get_customer_note(),
|
131 |
+
'locale' => get_locale(),
|
132 |
+
'metrics' => array(
|
133 |
+
'placed_at' => $this->server->format_datetime( $order->get_date_created()->getTimestamp() ),
|
134 |
+
'updated_at' => $this->server->format_datetime( $order->get_date_modified()->getTimestamp() ),
|
135 |
+
'fully_shipped_at' => null,
|
136 |
+
'expected_earliest_delivery_at' => null,
|
137 |
+
'expected_last_delivery_at' => null,
|
138 |
+
),
|
139 |
+
'customer' => array(
|
140 |
+
'id' => (string) $order->get_customer_id(),
|
141 |
+
'first_name' => $customer->get_first_name(),
|
142 |
+
'last_name' => $customer->get_last_name(),
|
143 |
+
'emails' => ( $customer->get_email() ) ? array( $customer->get_email() ) : array(),
|
144 |
+
'phones' => ( $customer->get_billing_phone() ) ? array(
|
145 |
+
array(
|
146 |
+
'country_code' => null,
|
147 |
+
'number' => $customer->get_billing_phone(),
|
148 |
+
),
|
149 |
+
) : array(),
|
150 |
+
),
|
151 |
+
'shipping_address' => array(
|
152 |
+
'first_name' => $order->get_shipping_first_name(),
|
153 |
+
'last_name' => $order->get_shipping_last_name(),
|
154 |
+
'company' => $order->get_shipping_company(),
|
155 |
+
'address_line_1' => $order->get_shipping_address_1(),
|
156 |
+
'address_line_2' => $order->get_shipping_address_2(),
|
157 |
+
'city' => $order->get_shipping_city(),
|
158 |
+
'state' => $order->get_shipping_state(),
|
159 |
+
'country' => $this->server->convert_country_code( $order->get_shipping_country() ),
|
160 |
+
'postal_code' => $order->get_shipping_postcode(),
|
161 |
+
'email' => $order->get_billing_email(),
|
162 |
+
'phone' => array(
|
163 |
+
'country_code' => null,
|
164 |
+
'number' => $order->get_billing_phone(),
|
165 |
+
),
|
166 |
+
'address_type' => null,
|
167 |
+
'tax_number' => null,
|
168 |
+
),
|
169 |
+
'billing_address' => array(
|
170 |
+
'first_name' => $order->get_billing_first_name(),
|
171 |
+
'last_name' => $order->get_billing_last_name(),
|
172 |
+
'company' => $order->get_billing_company(),
|
173 |
+
'address_line_1' => $order->get_billing_address_1(),
|
174 |
+
'address_line_2' => $order->get_billing_address_2(),
|
175 |
+
'city' => $order->get_billing_city(),
|
176 |
+
'state' => $order->get_billing_state(),
|
177 |
+
'postal_code' => $order->get_billing_postcode(),
|
178 |
+
'country' => $this->server->convert_country_code( $order->get_billing_country() ),
|
179 |
+
'email' => $order->get_billing_email(),
|
180 |
+
'phone' => array(
|
181 |
+
'country_code' => null,
|
182 |
+
'number' => $order->get_billing_phone(),
|
183 |
+
),
|
184 |
+
'address_type' => null,
|
185 |
+
'tax_number' => null,
|
186 |
+
),
|
187 |
+
'status' => $order->get_status(),
|
188 |
+
'items' => array(),
|
189 |
+
'trackings' => array(),
|
190 |
+
);
|
191 |
+
|
192 |
+
foreach ( $order->get_items() as $item_id => $item ) {
|
193 |
+
if ( is_callable( $item, 'get_product' ) ) {
|
194 |
+
$product = $item->get_product();
|
195 |
+
} else {
|
196 |
+
$product = $order->get_product_from_item( $item );
|
197 |
+
}
|
198 |
+
|
199 |
+
$product_id = 0;
|
200 |
+
$variation_id = 0;
|
201 |
+
$product_sku = null;
|
202 |
+
$weight = '';
|
203 |
+
$product_image_id = 0;
|
204 |
+
|
205 |
+
// Check if the product exists.
|
206 |
+
if ( is_object( $product ) ) {
|
207 |
+
$product_id = $item->get_product_id();
|
208 |
+
$variation_id = $item->get_variation_id();
|
209 |
+
$product_sku = $product->get_sku();
|
210 |
+
$weight = $product->get_weight();
|
211 |
+
$product_image_id = $product->get_image_id();
|
212 |
+
}
|
213 |
+
$subtotal = wc_format_decimal( $order->get_line_subtotal( $item, false, false ), $dp );
|
214 |
+
$total = wc_format_decimal( $order->get_line_total( $item, false, false ), $dp );
|
215 |
+
$terms_tags = get_the_terms( $product_id, 'product_tag' );
|
216 |
+
$product_tags = array();
|
217 |
+
foreach ( $terms_tags as $termsKey => $termsVal ) {
|
218 |
+
$product_tags[] = $termsVal->name;
|
219 |
+
}
|
220 |
+
$product_categories = array();
|
221 |
+
|
222 |
+
$categories = get_the_terms( $product_id, 'product_cat' );
|
223 |
+
foreach ( $categories as $categoriesKey => $categoriesVal ) {
|
224 |
+
$product_categories[] = $categoriesVal->name;
|
225 |
+
}
|
226 |
+
$order_data['items'][] = array(
|
227 |
+
'id' => (string) $item_id,
|
228 |
+
'product_id' => $product_id ? (string) $product_id : null,
|
229 |
+
'variant_id' => $variation_id ? (string) $variation_id : null,
|
230 |
+
'sku' => $product_sku,
|
231 |
+
'title' => $item['name'],
|
232 |
+
'quantity' => (int) $item['qty'],
|
233 |
+
'returnable_quantity' => (int) ( $item['qty'] - abs( $order->get_qty_refunded_for_item( $item_id ) ) ),
|
234 |
+
'unit_weight' => array(
|
235 |
+
'unit' => $weight_unit,
|
236 |
+
'value' => $weight === '' ? null : (float) $weight,
|
237 |
+
),
|
238 |
+
'unit_price' => array(
|
239 |
+
'currency' => $order->get_currency(),
|
240 |
+
'amount' => round( floatval( $subtotal ) / intval( $item['qty'] ), $dp ),
|
241 |
+
),
|
242 |
+
'discount' => array(
|
243 |
+
'currency' => $order->get_currency(),
|
244 |
+
'amount' => (float) ( $subtotal - $total ),
|
245 |
+
),
|
246 |
+
'image_urls' => $product_image_id && wp_get_attachment_url( $product_image_id ) ? array( wp_get_attachment_url( $product_image_id ) ) : array(),
|
247 |
+
'tags' => $product_tags,
|
248 |
+
'categories' => $product_categories,
|
249 |
+
);
|
250 |
+
}
|
251 |
+
|
252 |
+
$trackings = array();
|
253 |
+
// The function definition will be available after installing the aftership plugin.
|
254 |
+
if ( function_exists( 'order_post_meta_getter' ) ) {
|
255 |
+
$aftership_tracking_number = order_post_meta_getter( $order, 'aftership_tracking_number' );
|
256 |
+
if ( ! empty( $aftership_tracking_number ) ) {
|
257 |
+
$trackings[] = array(
|
258 |
+
'slug' => order_post_meta_getter( $order, 'aftership_tracking_provider' ),
|
259 |
+
'tracking_number' => $aftership_tracking_number,
|
260 |
+
'additional_fields' => array(
|
261 |
+
'account_number' => order_post_meta_getter( $order, 'aftership_tracking_account' ),
|
262 |
+
'key' => order_post_meta_getter( $order, 'aftership_tracking_key' ),
|
263 |
+
'postal_code' => order_post_meta_getter( $order, 'aftership_tracking_postal' ),
|
264 |
+
'ship_date' => order_post_meta_getter( $order, 'aftership_tracking_shipdate' ),
|
265 |
+
'destination_country' => order_post_meta_getter( $order, 'aftership_tracking_destination_country' ),
|
266 |
+
'state' => null,
|
267 |
+
'origin_country' => null,
|
268 |
+
),
|
269 |
+
);
|
270 |
+
}
|
271 |
+
|
272 |
+
// 兼容 wooCommerce 官方的 tracking 插件.
|
273 |
+
$woocommerce_tracking_arr = order_post_meta_getter( $order, 'wc_shipment_tracking_items' );
|
274 |
+
if ( empty( $aftership_tracking_number ) && ! empty( $woocommerce_tracking_arr ) ) {
|
275 |
+
foreach ( $woocommerce_tracking_arr as $trackingKey => $trackingVal ) {
|
276 |
+
$trackingInfo = $this->getTrackingInfoByShipmentTracking( $trackingVal );
|
277 |
+
$trackings[] = array(
|
278 |
+
'slug' => ! empty( $trackingInfo ) ? $trackingInfo['tracking_provider'] : $trackingVal['tracking_provider'],
|
279 |
+
'tracking_number' => $trackingVal['tracking_number'],
|
280 |
+
'additional_fields' => array(
|
281 |
+
'account_number' => null,
|
282 |
+
'key' => null,
|
283 |
+
'postal_code' => ! empty( $trackingInfo ) ? $trackingInfo['tracking_postal_code'] : null,
|
284 |
+
'ship_date' => null,
|
285 |
+
'destination_country' => null,
|
286 |
+
'state' => null,
|
287 |
+
'origin_country' => null,
|
288 |
+
),
|
289 |
+
);
|
290 |
+
}
|
291 |
+
}
|
292 |
+
}
|
293 |
+
$tracking_items = aftership()->actions->get_tracking_items_for_api( $id );
|
294 |
+
$order_data['trackings'] = $this->uniquify_tracking_items( array_merge( $trackings, $tracking_items ) );
|
295 |
+
|
296 |
+
return apply_filters( 'aftership_api_order_response', $order_data, $order, $fields, $this->server );
|
297 |
+
}
|
298 |
+
|
299 |
+
|
300 |
+
/**
|
301 |
+
* Uniquify tracking items by tracking id
|
302 |
+
*
|
303 |
+
* @param array $tracking_items all tracking items.
|
304 |
+
* @return array
|
305 |
+
*/
|
306 |
+
private function uniquify_tracking_items( $tracking_items ) {
|
307 |
+
$uniq_tracking_items = array();
|
308 |
+
// Add tracking id for all tracking item.
|
309 |
+
foreach ( $tracking_items as $t => $tracking_item ) {
|
310 |
+
if ( ! isset( $tracking_item['tracking_id'] ) ) {
|
311 |
+
$tracking_items[ $t ]['tracking_id'] = md5( "{$tracking_item['slug']}-{$tracking_item['tracking_number']}" );
|
312 |
+
}
|
313 |
+
}
|
314 |
+
$tracking_ids = array_unique( array_column( $tracking_items, 'tracking_id' ) );
|
315 |
+
|
316 |
+
foreach ( $tracking_ids as $tracking_id ) {
|
317 |
+
$found_key = array_search( $tracking_id, array_column( $tracking_items, 'tracking_id' ), true );
|
318 |
+
$uniq_tracking_items[] = $tracking_items[ $found_key ];
|
319 |
+
}
|
320 |
+
return $uniq_tracking_items;
|
321 |
+
}
|
322 |
+
|
323 |
+
/**
|
324 |
+
* 从wc ShipmentTracking 插件获取 Postalcode - postnl
|
325 |
+
*
|
326 |
+
* @param array $tracking_items Shipment tracking's tracking items.
|
327 |
+
* @return array
|
328 |
+
*/
|
329 |
+
private function getTrackingInfoByShipmentTracking( $tracking_items ) {
|
330 |
+
if ( ! isset( $tracking_items['custom_tracking_link'] ) ) {
|
331 |
+
return array();
|
332 |
+
}
|
333 |
+
|
334 |
+
// 获取 postnl Postalcode.
|
335 |
+
$urlArr = parse_url( stripslashes( $tracking_items['custom_tracking_link'] ) );
|
336 |
+
|
337 |
+
if ( $urlArr === false ) {
|
338 |
+
return array();
|
339 |
+
}
|
340 |
+
|
341 |
+
if ( ! isset( $urlArr['host'] ) ) {
|
342 |
+
return array();
|
343 |
+
}
|
344 |
+
|
345 |
+
$hostArr = explode( '.', $urlArr['host'] );
|
346 |
+
$hostArrIndex = count( $hostArr ) - 2;
|
347 |
+
if ( empty( $hostArr ) || ! isset( $hostArr[ $hostArrIndex ] ) ) {
|
348 |
+
return array();
|
349 |
+
}
|
350 |
+
|
351 |
+
if ( $hostArr[ $hostArrIndex ] == 'postnl' ) {
|
352 |
+
parse_str( $urlArr['query'], $queryArr );
|
353 |
+
if ( ! isset( $queryArr['Postalcode'] ) ) {
|
354 |
+
return array();
|
355 |
+
}
|
356 |
+
|
357 |
+
return array(
|
358 |
+
'tracking_provider' => 'postnl',
|
359 |
+
'tracking_postal_code' => str_replace( ' ', '', $queryArr['Postalcode'] ),
|
360 |
+
);
|
361 |
+
}
|
362 |
+
return array();
|
363 |
+
}
|
364 |
+
|
365 |
+
|
366 |
+
/**
|
367 |
+
* Helper method to get order post objects
|
368 |
+
*
|
369 |
+
* @param array $args request arguments for filtering query.
|
370 |
+
*
|
371 |
+
* @return WP_Query
|
372 |
+
* @since 2.1
|
373 |
+
*/
|
374 |
+
private function query_orders( $args ) {
|
375 |
+
|
376 |
+
/**
|
377 |
+
* Get wooCommerce version number.
|
378 |
+
*
|
379 |
+
* @return string|null
|
380 |
+
*/
|
381 |
+
function aftership_wpbo_get_woo_version_number() {
|
382 |
+
// If get_plugins() isn't available, require it.
|
383 |
+
if ( ! function_exists( 'get_plugins' ) ) {
|
384 |
+
require_once( ABSPATH . 'wp-admin/includes/plugin.php' );
|
385 |
+
}
|
386 |
+
|
387 |
+
// Create the plugins folder and file variables.
|
388 |
+
$plugin_folder = get_plugins( '/' . 'woocommerce' );
|
389 |
+
$plugin_file = 'woocommerce.php';
|
390 |
+
|
391 |
+
// If the plugin version number is set, return it.
|
392 |
+
if ( isset( $plugin_folder[ $plugin_file ]['Version'] ) ) {
|
393 |
+
return $plugin_folder[ $plugin_file ]['Version'];
|
394 |
+
|
395 |
+
} else {
|
396 |
+
// Otherwise return null.
|
397 |
+
return null;
|
398 |
+
}
|
399 |
+
}
|
400 |
+
|
401 |
+
$woo_version = aftership_wpbo_get_woo_version_number();
|
402 |
+
|
403 |
+
if ( $woo_version >= 2.2 ) {
|
404 |
+
// set base query arguments.
|
405 |
+
$query_args = array(
|
406 |
+
'fields' => 'ids',
|
407 |
+
'post_type' => 'shop_order',
|
408 |
+
// 'post_status' => 'publish',
|
409 |
+
'post_status' => array_keys( wc_get_order_statuses() ),
|
410 |
+
);
|
411 |
+
} else {
|
412 |
+
// set base query arguments.
|
413 |
+
$query_args = array(
|
414 |
+
'fields' => 'ids',
|
415 |
+
'post_type' => 'shop_order',
|
416 |
+
'post_status' => 'publish',
|
417 |
+
);
|
418 |
+
}
|
419 |
+
|
420 |
+
// add status argument.
|
421 |
+
if ( ! empty( $args['status'] ) ) {
|
422 |
+
|
423 |
+
$statuses = explode( ',', $args['status'] );
|
424 |
+
|
425 |
+
$query_args['tax_query'] = array(
|
426 |
+
array(
|
427 |
+
'taxonomy' => 'shop_order_status',
|
428 |
+
'field' => 'slug',
|
429 |
+
'terms' => $statuses,
|
430 |
+
),
|
431 |
+
);
|
432 |
+
|
433 |
+
unset( $args['status'] );
|
434 |
+
}
|
435 |
+
|
436 |
+
$query_args = $this->merge_query_args( $query_args, $args );
|
437 |
+
|
438 |
+
return new WP_Query( $query_args );
|
439 |
+
}
|
440 |
+
|
441 |
+
}
|
includes/api/v4/class-aftership-api-settings.php
ADDED
@@ -0,0 +1,80 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
if ( ! defined( 'ABSPATH' ) ) {
|
4 |
+
exit;
|
5 |
+
}
|
6 |
+
|
7 |
+
/**
|
8 |
+
* AfterShip API settings
|
9 |
+
*/
|
10 |
+
class AfterShip_API_V4_Settings extends AfterShip_API_Resource {
|
11 |
+
|
12 |
+
/**
|
13 |
+
* Base router.
|
14 |
+
*
|
15 |
+
* @var string $base base router.
|
16 |
+
*/
|
17 |
+
protected $base = '/v4/settings';
|
18 |
+
|
19 |
+
/**
|
20 |
+
* Register the routes for this class
|
21 |
+
*
|
22 |
+
* @param array $routes routes list.
|
23 |
+
*
|
24 |
+
* @return array
|
25 |
+
*/
|
26 |
+
public function register_routes( $routes ) {
|
27 |
+
|
28 |
+
$routes[ $this->base ] = array(
|
29 |
+
// GET list API.
|
30 |
+
array( array( $this, 'get_list' ), AfterShip_API_Server::READABLE ),
|
31 |
+
// PUT or POST API.
|
32 |
+
array( array( $this, 'update' ), AfterShip_API_Server::METHOD_POST | AfterShip_API_Server::METHOD_PUT | AfterShip_API_Server::ACCEPT_DATA ),
|
33 |
+
);
|
34 |
+
|
35 |
+
return $routes;
|
36 |
+
}
|
37 |
+
|
38 |
+
/**
|
39 |
+
* GET all settings.
|
40 |
+
*
|
41 |
+
* @return array
|
42 |
+
*/
|
43 |
+
public function get_list() {
|
44 |
+
return array( 'settings' => get_option( 'aftership_option_name' ) );
|
45 |
+
}
|
46 |
+
|
47 |
+
/**
|
48 |
+
* Update plugin settings.
|
49 |
+
*
|
50 |
+
* @param array $data JSON data from post request.
|
51 |
+
* @return array|WP_Error
|
52 |
+
*/
|
53 |
+
public function update( $data ) {
|
54 |
+
$options = get_option( 'aftership_option_name' );
|
55 |
+
$custom_domain = isset( $options['custom_domain'] ) ? $options['custom_domain'] : '';
|
56 |
+
$couriers = isset( $options['couriers'] ) ? $options['couriers'] : '';
|
57 |
+
$use_tracking_button = isset( $options['use_track_button'] ) ? $options['use_track_button'] : '';
|
58 |
+
|
59 |
+
if ( isset( $data['custom_domain'] ) && $data['custom_domain'] ) {
|
60 |
+
if ( 'track.aftership.com' === $custom_domain || '' === $custom_domain ) {
|
61 |
+
$options['custom_domain'] = $data['custom_domain'];
|
62 |
+
}
|
63 |
+
}
|
64 |
+
|
65 |
+
if ( isset( $data['couriers'] ) && $data['couriers'] ) {
|
66 |
+
if ( '' === $couriers ) {
|
67 |
+
$options['couriers'] = $data['couriers'];
|
68 |
+
}
|
69 |
+
}
|
70 |
+
|
71 |
+
if ( isset( $data['use_track_button'] ) && in_array( $data['use_track_button'], array( true, false ), true ) ) {
|
72 |
+
if ( '' === $use_tracking_button ) {
|
73 |
+
$options['use_track_button'] = $data['use_track_button'];
|
74 |
+
}
|
75 |
+
}
|
76 |
+
update_option( 'aftership_option_name', $options );
|
77 |
+
return array( 'settings' => $options );
|
78 |
+
}
|
79 |
+
|
80 |
+
}
|
includes/class-aftership-actions.php
ADDED
@@ -0,0 +1,833 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
if ( ! defined( 'ABSPATH' ) ) {
|
3 |
+
exit;
|
4 |
+
}
|
5 |
+
|
6 |
+
/**
|
7 |
+
* AfterShip Actions
|
8 |
+
*/
|
9 |
+
class AfterShip_Actions {
|
10 |
+
|
11 |
+
|
12 |
+
/**
|
13 |
+
* Instance of this class.
|
14 |
+
*
|
15 |
+
* @var object Class Instance
|
16 |
+
*/
|
17 |
+
private static $instance;
|
18 |
+
|
19 |
+
/**
|
20 |
+
* Get the class instance
|
21 |
+
*
|
22 |
+
* @return AfterShip_Actions
|
23 |
+
*/
|
24 |
+
public static function get_instance() {
|
25 |
+
if ( null === self::$instance ) {
|
26 |
+
|
27 |
+
self::$instance = new self;
|
28 |
+
}
|
29 |
+
|
30 |
+
return self::$instance;
|
31 |
+
}
|
32 |
+
|
33 |
+
/**
|
34 |
+
* Get courier detail by slug
|
35 |
+
*
|
36 |
+
* @param string $slug
|
37 |
+
* @return array
|
38 |
+
*/
|
39 |
+
public function get_courier_by_slug( $slug ) {
|
40 |
+
$courier = array();
|
41 |
+
foreach ( $GLOBALS['AfterShip']->couriers as $item ) {
|
42 |
+
if ( $item['slug'] == $slug ) {
|
43 |
+
$courier = $item;
|
44 |
+
}
|
45 |
+
}
|
46 |
+
return $courier;
|
47 |
+
}
|
48 |
+
|
49 |
+
/**
|
50 |
+
* Localisation.
|
51 |
+
*/
|
52 |
+
public function load_plugin_textdomain() {
|
53 |
+
$plugin_file = $GLOBALS['AfterShip']->plugin_file;
|
54 |
+
load_plugin_textdomain( 'aftership', false, dirname( plugin_basename( $plugin_file ) ) . '/languages/' );
|
55 |
+
}
|
56 |
+
|
57 |
+
/**
|
58 |
+
* Load admin styles.
|
59 |
+
*/
|
60 |
+
public function admin_styles() {
|
61 |
+
$plugin_url = $GLOBALS['AfterShip']->plugin_url;
|
62 |
+
wp_enqueue_style( 'aftership_styles', $plugin_url . '/assets/css/admin.css' );
|
63 |
+
}
|
64 |
+
|
65 |
+
/**
|
66 |
+
* Add the meta box for shipment info on the order page
|
67 |
+
*/
|
68 |
+
public function add_meta_box() {
|
69 |
+
add_meta_box( 'woocommerce-aftership', __( 'AfterShip', 'aftership' ), array( $this, 'meta_box' ), 'shop_order', 'side', 'high' );
|
70 |
+
}
|
71 |
+
|
72 |
+
/**
|
73 |
+
* Returns a HTML node for a tracking item for the admin meta box
|
74 |
+
*
|
75 |
+
* @param $order_id string
|
76 |
+
* @param $item array
|
77 |
+
* @param $index number
|
78 |
+
*/
|
79 |
+
public function display_html_tracking_item_for_meta_box( $order_id, $item, $index ) {
|
80 |
+
$courier = $this->get_courier_by_slug( $item['slug'] );
|
81 |
+
$link = $this->generate_tracking_page_link( $item );
|
82 |
+
?>
|
83 |
+
<div
|
84 |
+
class="tracking-item"
|
85 |
+
data-tracking="<?php echo esc_html( $item['tracking_number'] ); ?>"
|
86 |
+
data-slug="<?php echo esc_html( $item['slug'] ); ?>"
|
87 |
+
id="tracking-item-<?php echo esc_attr( $item['tracking_id'] ); ?>"
|
88 |
+
>
|
89 |
+
<div class="tracking-item-title">
|
90 |
+
<div>Shipment <?php echo esc_html( $index ); ?></div>
|
91 |
+
<div>
|
92 |
+
<a
|
93 |
+
href="#"
|
94 |
+
class="edit-tracking"
|
95 |
+
rel="<?php echo esc_attr( $item['tracking_id'] ); ?>"
|
96 |
+
>
|
97 |
+
<?php _e( 'Edit', 'aftership' ); ?>
|
98 |
+
</a>
|
99 |
+
<a
|
100 |
+
href="#" class="delete-tracking"
|
101 |
+
rel="<?php echo esc_attr( $item['tracking_id'] ); ?>"
|
102 |
+
>
|
103 |
+
<?php _e( 'Delete', 'aftership' ); ?>
|
104 |
+
</a>
|
105 |
+
</div>
|
106 |
+
</div>
|
107 |
+
<div class="tracking-item-content">
|
108 |
+
<div>
|
109 |
+
<strong><?php echo esc_html( $courier['name'] ); ?></strong>
|
110 |
+
</div>
|
111 |
+
<div>
|
112 |
+
<a target="_blank" href="<?php echo esc_html( $link ); ?>">
|
113 |
+
<?php echo esc_html( $item['tracking_number'] ); ?>
|
114 |
+
</a>
|
115 |
+
</div>
|
116 |
+
</div>
|
117 |
+
|
118 |
+
</div>
|
119 |
+
<?php
|
120 |
+
}
|
121 |
+
|
122 |
+
/**
|
123 |
+
* Generate tracking page links
|
124 |
+
*
|
125 |
+
* @param $item
|
126 |
+
* @return string
|
127 |
+
*/
|
128 |
+
public function generate_tracking_page_link( $item ) {
|
129 |
+
$custom_domain = $GLOBALS['AfterShip']->custom_domain;
|
130 |
+
$contains_http = strpos( $custom_domain, 'http://' );
|
131 |
+
$contains_https = strpos( $custom_domain, 'https://' );
|
132 |
+
if ( $contains_http !== false || $contains_https !== false ) {
|
133 |
+
return $custom_domain . "/${item['slug']}/${item['tracking_number']}";
|
134 |
+
}
|
135 |
+
return 'https://' . $custom_domain . "/${item['slug']}/${item['tracking_number']}";
|
136 |
+
}
|
137 |
+
|
138 |
+
/**
|
139 |
+
* Show the meta box for shipment info on the order page
|
140 |
+
*/
|
141 |
+
public function meta_box() {
|
142 |
+
global $post;
|
143 |
+
|
144 |
+
$tracking_items = $this->get_tracking_items( $post->ID );
|
145 |
+
|
146 |
+
echo '<div id="tracking-items">';
|
147 |
+
$count = 1;
|
148 |
+
if ( count( $tracking_items ) > 0 ) {
|
149 |
+
foreach ( $tracking_items as $index => $tracking_item ) {
|
150 |
+
$this->display_html_tracking_item_for_meta_box( $post->ID, $tracking_item, $count );
|
151 |
+
$count++;
|
152 |
+
}
|
153 |
+
}
|
154 |
+
|
155 |
+
echo '</div>';
|
156 |
+
echo '<div class="show-form-btn-container" style="padding: 12px;">';
|
157 |
+
echo '<button class="button button-show-form" type="button">' . __( 'Add Tracking Number', 'aftership' ) . '</button>';
|
158 |
+
echo '</div>';
|
159 |
+
echo '<div id="aftership-tracking-form">';
|
160 |
+
echo '<p class="form-field aftership_tracking_slug_field">';
|
161 |
+
echo '<label for="aftership_tracking_slug">' . __( 'Courier:', 'aftership' ) . '</label>';
|
162 |
+
echo '<select id="aftership_tracking_slug" name="aftership_tracking_slug" class="chosen_select" style="width:100%;">';
|
163 |
+
foreach ( $GLOBALS['AfterShip']->selected_couriers as $courier ) {
|
164 |
+
echo '<option value="' . esc_attr( sanitize_title( $courier['slug'] ) ) . '">' . esc_html( $courier['name'] ) . '</option>';
|
165 |
+
}
|
166 |
+
echo '</select>';
|
167 |
+
echo '<a class="link-to-setting" href="options-general.php?page=aftership-setting-admin">Update carrier list</a>';
|
168 |
+
echo '</p>';
|
169 |
+
|
170 |
+
$options = array();
|
171 |
+
foreach ( $GLOBALS['AfterShip']->selected_couriers as $courier ) {
|
172 |
+
$options[ sanitize_title( $courier['slug'] ) ] = $courier['name'];
|
173 |
+
}
|
174 |
+
|
175 |
+
woocommerce_wp_hidden_input(
|
176 |
+
array(
|
177 |
+
'id' => 'aftership_get_nonce',
|
178 |
+
'value' => wp_create_nonce( 'get-tracking-item' ),
|
179 |
+
)
|
180 |
+
);
|
181 |
+
|
182 |
+
woocommerce_wp_hidden_input(
|
183 |
+
array(
|
184 |
+
'id' => 'aftership_delete_nonce',
|
185 |
+
'value' => wp_create_nonce( 'delete-tracking-item' ),
|
186 |
+
)
|
187 |
+
);
|
188 |
+
|
189 |
+
woocommerce_wp_hidden_input(
|
190 |
+
array(
|
191 |
+
'id' => 'aftership_create_nonce',
|
192 |
+
'value' => wp_create_nonce( 'create-tracking-item' ),
|
193 |
+
)
|
194 |
+
);
|
195 |
+
|
196 |
+
woocommerce_wp_hidden_input(
|
197 |
+
array(
|
198 |
+
'id' => 'aftership_tracking_id',
|
199 |
+
'value' => '',
|
200 |
+
)
|
201 |
+
);
|
202 |
+
|
203 |
+
woocommerce_wp_text_input(
|
204 |
+
array(
|
205 |
+
'id' => 'aftership_tracking_number',
|
206 |
+
'label' => __( 'Tracking number:', 'aftership' ),
|
207 |
+
'placeholder' => '',
|
208 |
+
'description' => '',
|
209 |
+
'value' => '',
|
210 |
+
)
|
211 |
+
);
|
212 |
+
|
213 |
+
woocommerce_wp_text_input(
|
214 |
+
array(
|
215 |
+
'id' => 'aftership_tracking_account_number',
|
216 |
+
'label' => __( 'Account number:', 'aftership' ),
|
217 |
+
'placeholder' => '',
|
218 |
+
'description' => '',
|
219 |
+
'value' => '',
|
220 |
+
)
|
221 |
+
);
|
222 |
+
|
223 |
+
woocommerce_wp_text_input(
|
224 |
+
array(
|
225 |
+
'id' => 'aftership_tracking_key',
|
226 |
+
'label' => __( 'Account key:', 'aftership' ),
|
227 |
+
'placeholder' => '',
|
228 |
+
'description' => '',
|
229 |
+
'value' => '',
|
230 |
+
)
|
231 |
+
);
|
232 |
+
|
233 |
+
woocommerce_wp_text_input(
|
234 |
+
array(
|
235 |
+
'id' => 'aftership_tracking_postal_code',
|
236 |
+
'label' => __( 'Postal code:', 'aftership' ),
|
237 |
+
'placeholder' => '',
|
238 |
+
'description' => '',
|
239 |
+
'value' => '',
|
240 |
+
)
|
241 |
+
);
|
242 |
+
|
243 |
+
woocommerce_wp_text_input(
|
244 |
+
array(
|
245 |
+
'id' => 'aftership_tracking_ship_date',
|
246 |
+
'label' => __( 'Date shipped:', 'aftership' ),
|
247 |
+
'placeholder' => date_i18n( __( 'Y-m-d', 'aftership' ), time() ),
|
248 |
+
'description' => '',
|
249 |
+
'class' => 'date-picker-field',
|
250 |
+
'value' => date_i18n( __( 'Y-m-d', 'aftership' ), current_time( 'timestamp' ) ),
|
251 |
+
)
|
252 |
+
);
|
253 |
+
|
254 |
+
woocommerce_wp_text_input(
|
255 |
+
array(
|
256 |
+
'id' => 'aftership_tracking_destination_country',
|
257 |
+
'label' => __( 'Ship Destination Country (ISO3):', 'aftership' ),
|
258 |
+
'placeholder' => '',
|
259 |
+
'description' => '',
|
260 |
+
'value' => '',
|
261 |
+
)
|
262 |
+
);
|
263 |
+
|
264 |
+
woocommerce_wp_text_input(
|
265 |
+
array(
|
266 |
+
'id' => 'aftership_tracking_state',
|
267 |
+
'label' => __( 'Ship State:', 'aftership' ),
|
268 |
+
'placeholder' => '',
|
269 |
+
'description' => '',
|
270 |
+
'value' => '',
|
271 |
+
)
|
272 |
+
);
|
273 |
+
|
274 |
+
echo '<div style="padding: 9px 0px 4px 0px;">';
|
275 |
+
echo '<button class="button button-primary button-save-form">' . __( 'Save', 'aftership' ) . '</button>';
|
276 |
+
echo '<button class="button button-cancel">' . __( 'Cancel', 'aftership' ) . '</button>';
|
277 |
+
echo '</div>';
|
278 |
+
|
279 |
+
echo '</div>';
|
280 |
+
|
281 |
+
$js = "
|
282 |
+
$('p.aftership_tracking_key_field').hide();
|
283 |
+
$('p.aftership_tracking_account_number_field').hide();
|
284 |
+
$('p.aftership_tracking_postal_code_field').hide();
|
285 |
+
$('p.aftership_tracking_ship_date_field').hide();
|
286 |
+
$('p.aftership_tracking_destination_country_field').hide();
|
287 |
+
$('p.aftership_tracking_state_field').hide();
|
288 |
+
jQuery('#aftership_tracking_slug').change( function() {
|
289 |
+
$('p.aftership_tracking_key_field').hide();
|
290 |
+
$('p.aftership_tracking_account_number_field').hide();
|
291 |
+
$('p.aftership_tracking_postal_code_field').hide();
|
292 |
+
$('p.aftership_tracking_ship_date_field').hide();
|
293 |
+
$('p.aftership_tracking_destination_country_field').hide();
|
294 |
+
$('p.aftership_tracking_state_field').hide();
|
295 |
+
var required_fields_mapping = {
|
296 |
+
tracking_key: 'aftership_tracking_key',
|
297 |
+
tracking_account_number: 'aftership_tracking_account_number',
|
298 |
+
tracking_postal_code: 'aftership_tracking_postal_code',
|
299 |
+
tracking_ship_date: 'aftership_tracking_ship_date',
|
300 |
+
tracking_destination_country: 'aftership_tracking_destination_country',
|
301 |
+
tracking_state: 'aftership_tracking_state',
|
302 |
+
};
|
303 |
+
var slug = jQuery( '#aftership_tracking_slug' ).val();
|
304 |
+
if (!slug) return;
|
305 |
+
var couriers = JSON.parse( decodeURIComponent( '" . rawurlencode( wp_json_encode( $GLOBALS['AfterShip']->selected_couriers ) ) . "' ) );
|
306 |
+
var courier = couriers.find(item => item.slug === slug);
|
307 |
+
var required_fields = courier.required_fields;
|
308 |
+
for (var field of required_fields) {
|
309 |
+
var field_name = required_fields_mapping[field];
|
310 |
+
$('p.' + field_name + '_field').show();
|
311 |
+
}
|
312 |
+
} ).change();";
|
313 |
+
|
314 |
+
if ( function_exists( 'wc_enqueue_js' ) ) {
|
315 |
+
wc_enqueue_js( $js );
|
316 |
+
} else {
|
317 |
+
WC()->add_inline_js( $js );
|
318 |
+
}
|
319 |
+
|
320 |
+
wp_enqueue_style( 'aftership_styles_chosen', aftership()->plugin_url . '/assets/plugin/chosen/chosen.min.css' );
|
321 |
+
wp_enqueue_script( 'aftership-js', $GLOBALS['AfterShip']->plugin_url . '/assets/js/meta-box.js' );
|
322 |
+
wp_enqueue_script( 'aftership-js', $GLOBALS['AfterShip']->plugin_url . '/assets/plugin/chosen/chosen.jquery.min.js' );
|
323 |
+
wp_enqueue_script( 'aftership-js', $GLOBALS['AfterShip']->plugin_url . '/assets/plugin/chosen/chosen.proto.min.js' );
|
324 |
+
|
325 |
+
}
|
326 |
+
|
327 |
+
/**
|
328 |
+
* Order Tracking Save
|
329 |
+
*
|
330 |
+
* Function for saving tracking items
|
331 |
+
*
|
332 |
+
* @param $post_id string
|
333 |
+
* @param $post array
|
334 |
+
*/
|
335 |
+
public function save_meta_box( $post_id, $post ) {
|
336 |
+
if ( isset( $_POST['aftership_tracking_number'] ) && strlen( $_POST['aftership_tracking_number'] ) > 0 ) {
|
337 |
+
$args = array(
|
338 |
+
'slug' => wc_clean( $_POST['aftership_tracking_slug'] ),
|
339 |
+
'tracking_number' => wc_clean( $_POST['aftership_tracking_number'] ),
|
340 |
+
'additional_fields' => array(
|
341 |
+
'account_number' => wc_clean( $_POST['aftership_tracking_account_number'] ),
|
342 |
+
'key' => wc_clean( $_POST['aftership_tracking_key'] ),
|
343 |
+
'postal_code' => wc_clean( $_POST['aftership_tracking_postal_code'] ),
|
344 |
+
'ship_date' => wc_clean( $_POST['aftership_tracking_ship_date'] ),
|
345 |
+
'destination_country' => wc_clean( $_POST['aftership_tracking_destination_country'] ),
|
346 |
+
'state' => wc_clean( $_POST['aftership_tracking_state'] ),
|
347 |
+
),
|
348 |
+
);
|
349 |
+
|
350 |
+
$this->add_tracking_item( $post_id, $args );
|
351 |
+
}
|
352 |
+
}
|
353 |
+
|
354 |
+
/**
|
355 |
+
* Order Tracking Get All Order Items AJAX
|
356 |
+
*
|
357 |
+
* Function for getting all tracking items associated with the order
|
358 |
+
*/
|
359 |
+
public function get_meta_box_items_ajax() {
|
360 |
+
check_ajax_referer( 'get-tracking-item', 'security', true );
|
361 |
+
|
362 |
+
$order_id = wc_clean( $_POST['order_id'] );
|
363 |
+
// migrate old tracking data
|
364 |
+
$this->convert_old_meta_in_order( $order_id );
|
365 |
+
$tracking_items = $this->get_tracking_items( $order_id );
|
366 |
+
|
367 |
+
$count = 1;
|
368 |
+
foreach ( $tracking_items as $index => $tracking_item ) {
|
369 |
+
$this->display_html_tracking_item_for_meta_box( $order_id, $tracking_item, $count );
|
370 |
+
$count++;
|
371 |
+
}
|
372 |
+
|
373 |
+
die();
|
374 |
+
}
|
375 |
+
|
376 |
+
/**
|
377 |
+
* Order Tracking Save AJAX
|
378 |
+
*
|
379 |
+
* Function for saving tracking items via AJAX
|
380 |
+
*
|
381 |
+
* @throws WC_Data_Exception
|
382 |
+
*/
|
383 |
+
public function save_meta_box_ajax() {
|
384 |
+
check_ajax_referer( 'create-tracking-item', 'security', true );
|
385 |
+
|
386 |
+
if ( isset( $_POST['aftership_tracking_number'] ) && strlen( $_POST['aftership_tracking_number'] ) > 0 ) {
|
387 |
+
|
388 |
+
$order_id = wc_clean( $_POST['order_id'] );
|
389 |
+
$args = array(
|
390 |
+
'slug' => wc_clean( $_POST['aftership_tracking_slug'] ),
|
391 |
+
'tracking_number' => wc_clean( $_POST['aftership_tracking_number'] ),
|
392 |
+
'additional_fields' => array(
|
393 |
+
'account_number' => wc_clean( $_POST['aftership_tracking_account_number'] ),
|
394 |
+
'key' => wc_clean( $_POST['aftership_tracking_key'] ),
|
395 |
+
'postal_code' => wc_clean( $_POST['aftership_tracking_postal_code'] ),
|
396 |
+
'ship_date' => wc_clean( $_POST['aftership_tracking_ship_date'] ),
|
397 |
+
'destination_country' => wc_clean( $_POST['aftership_tracking_destination_country'] ),
|
398 |
+
'state' => wc_clean( $_POST['aftership_tracking_state'] ),
|
399 |
+
),
|
400 |
+
);
|
401 |
+
|
402 |
+
$post_tracking_id = wc_clean( $_POST['aftership_tracking_id'] );
|
403 |
+
$tracking_id = md5( "{$args['slug']}-{$args['tracking_number']}" );
|
404 |
+
if ( $post_tracking_id && $tracking_id !== $post_tracking_id ) {
|
405 |
+
$this->delete_tracking_item( $order_id, $post_tracking_id );
|
406 |
+
}
|
407 |
+
$tracking_item = $this->add_tracking_item( $order_id, $args );
|
408 |
+
$order = new WC_Order( $order_id );
|
409 |
+
$order->set_date_modified( current_time( 'mysql' ) );
|
410 |
+
$order->save();
|
411 |
+
}
|
412 |
+
|
413 |
+
die();
|
414 |
+
}
|
415 |
+
|
416 |
+
/**
|
417 |
+
* Order Tracking Delete
|
418 |
+
*
|
419 |
+
* Function to delete a tracking item
|
420 |
+
*
|
421 |
+
* @throws WC_Data_Exception
|
422 |
+
*/
|
423 |
+
public function meta_box_delete_tracking() {
|
424 |
+
check_ajax_referer( 'delete-tracking-item', 'security', true );
|
425 |
+
|
426 |
+
$order_id = wc_clean( $_POST['order_id'] );
|
427 |
+
$tracking_id = wc_clean( $_POST['tracking_id'] );
|
428 |
+
|
429 |
+
$this->delete_tracking_item( $order_id, $tracking_id );
|
430 |
+
|
431 |
+
$order = new WC_Order( $order_id );
|
432 |
+
$order->set_date_modified( current_time( 'mysql' ) );
|
433 |
+
$order->save();
|
434 |
+
}
|
435 |
+
|
436 |
+
|
437 |
+
/**
|
438 |
+
* Get single tracking info
|
439 |
+
*
|
440 |
+
* Function to show tracking edit form
|
441 |
+
*/
|
442 |
+
public function get_meta_box_item_ajax() {
|
443 |
+
check_ajax_referer( 'get-tracking-item', 'security', true );
|
444 |
+
|
445 |
+
$order_id = wc_clean( $_POST['order_id'] );
|
446 |
+
$tracking_id = wc_clean( $_POST['tracking_id'] );
|
447 |
+
$tracking_item = $this->get_tracking_item( $order_id, $tracking_id );
|
448 |
+
$tracking_item['courier'] = $this->get_courier_by_slug( $tracking_item['slug'] );
|
449 |
+
header( 'Content-Type: application/json' );
|
450 |
+
echo json_encode( $tracking_item, true );
|
451 |
+
die();
|
452 |
+
}
|
453 |
+
|
454 |
+
/**
|
455 |
+
* Display Shipment info in the frontend (order view/tracking page).
|
456 |
+
*
|
457 |
+
* @param string $order_id
|
458 |
+
*/
|
459 |
+
public function display_tracking_info( $order_id ) {
|
460 |
+
wc_get_template(
|
461 |
+
'myaccount/view-order.php',
|
462 |
+
array(
|
463 |
+
'tracking_items' => $this->get_tracking_items_for_display( $order_id ),
|
464 |
+
'use_track_button' => $GLOBALS['AfterShip']->use_track_button,
|
465 |
+
'domain' => $GLOBALS['AfterShip']->custom_domain,
|
466 |
+
),
|
467 |
+
'aftership-woocommerce-tracking/',
|
468 |
+
$GLOBALS['AfterShip']->get_plugin_path() . '/templates/'
|
469 |
+
);
|
470 |
+
}
|
471 |
+
|
472 |
+
/**
|
473 |
+
* Display shipment info in customer emails.
|
474 |
+
*
|
475 |
+
* @param WC_Order $order Order object.
|
476 |
+
* @param bool $sent_to_admin Whether the email is being sent to admin or not.
|
477 |
+
* @param bool $plain_text Whether email is in plain text or not.
|
478 |
+
* @param WC_Email $email Email object.
|
479 |
+
*/
|
480 |
+
public function email_display( $order, $sent_to_admin, $plain_text = null, $email = null ) {
|
481 |
+
/**
|
482 |
+
* Don't include tracking information in refunded email.
|
483 |
+
*
|
484 |
+
* When email instance is `WC_Email_Customer_Refunded_Order`, it may
|
485 |
+
* full or partial refund.
|
486 |
+
*/
|
487 |
+
if ( is_a( $email, 'WC_Email_Customer_Refunded_Order' ) ) {
|
488 |
+
return;
|
489 |
+
}
|
490 |
+
|
491 |
+
$order_id = is_callable( array( $order, 'get_id' ) ) ? $order->get_id() : $order->id;
|
492 |
+
if ( true === $plain_text ) {
|
493 |
+
wc_get_template( 'email/plain/tracking-info.php', array( 'tracking_items' => $this->get_tracking_items_for_display( $order_id ) ), 'aftership-woocommerce-tracking/', $GLOBALS['AfterShip']->get_plugin_path() . '/templates/' );
|
494 |
+
} else {
|
495 |
+
wc_get_template( 'email/tracking-info.php', array( 'tracking_items' => $this->get_tracking_items_for_display( $order_id ) ), 'aftership-woocommerce-tracking/', $GLOBALS['AfterShip']->get_plugin_path() . '/templates/' );
|
496 |
+
}
|
497 |
+
}
|
498 |
+
|
499 |
+
/**
|
500 |
+
* Prevents data being copied to subscription renewals
|
501 |
+
*/
|
502 |
+
public function woocommerce_subscriptions_renewal_order_meta_query( $order_meta_query, $original_order_id, $renewal_order_id, $new_order_role ) {
|
503 |
+
$order_meta_query .= " AND `meta_key` NOT IN ( '_aftership_tracking_items' )";
|
504 |
+
return $order_meta_query;
|
505 |
+
}
|
506 |
+
|
507 |
+
/**
|
508 |
+
* Deletes a tracking item from post_meta array
|
509 |
+
*
|
510 |
+
* @param int $order_id Order ID
|
511 |
+
* @param string $tracking_id Tracking ID
|
512 |
+
*
|
513 |
+
* @return bool True if tracking item is deleted successfully
|
514 |
+
*/
|
515 |
+
public function delete_tracking_item( $order_id, $tracking_id ) {
|
516 |
+
$tracking_items = $this->get_tracking_items( $order_id );
|
517 |
+
|
518 |
+
$is_deleted = false;
|
519 |
+
|
520 |
+
if ( count( $tracking_items ) > 0 ) {
|
521 |
+
foreach ( $tracking_items as $key => $item ) {
|
522 |
+
if ( $item['tracking_id'] == $tracking_id ) {
|
523 |
+
unset( $tracking_items[ $key ] );
|
524 |
+
$is_deleted = true;
|
525 |
+
break;
|
526 |
+
}
|
527 |
+
}
|
528 |
+
$this->save_tracking_items( $order_id, $tracking_items );
|
529 |
+
}
|
530 |
+
|
531 |
+
return $is_deleted;
|
532 |
+
}
|
533 |
+
|
534 |
+
/*
|
535 |
+
* Adds a tracking item to the post_meta array, no repeat items
|
536 |
+
*
|
537 |
+
* @param int $order_id Order ID
|
538 |
+
* @param array $tracking_items List of tracking item
|
539 |
+
*
|
540 |
+
* @return array Tracking item
|
541 |
+
*/
|
542 |
+
public function add_tracking_item( $order_id, $args ) {
|
543 |
+
$tracking_item = array();
|
544 |
+
$tracking_item['slug'] = wc_clean( $args['slug'] );
|
545 |
+
$tracking_item['tracking_number'] = wc_clean( $args['tracking_number'] );
|
546 |
+
$tracking_item['tracking_id'] = md5( "{$tracking_item['slug']}-{$tracking_item['tracking_number']}" );
|
547 |
+
$tracking_item['additional_fields'] = array(
|
548 |
+
'account_number' => wc_clean( $args['additional_fields']['account_number'] ),
|
549 |
+
'key' => wc_clean( $args['additional_fields']['key'] ),
|
550 |
+
'postal_code' => wc_clean( $args['additional_fields']['postal_code'] ),
|
551 |
+
'ship_date' => wc_clean( $args['additional_fields']['ship_date'] ),
|
552 |
+
'destination_country' => wc_clean( $args['additional_fields']['destination_country'] ),
|
553 |
+
'state' => wc_clean( $args['additional_fields']['state'] ),
|
554 |
+
);
|
555 |
+
$tracking_items = $this->get_tracking_items( $order_id );
|
556 |
+
$exist = false;
|
557 |
+
foreach ( $tracking_items as $key => $item ) {
|
558 |
+
if ( $item['tracking_id'] == $tracking_item['tracking_id'] ) {
|
559 |
+
$exist = true;
|
560 |
+
$tracking_items[ $key ] = $tracking_item;
|
561 |
+
}
|
562 |
+
}
|
563 |
+
if ( ! $exist ) {
|
564 |
+
$tracking_items[] = $tracking_item;
|
565 |
+
}
|
566 |
+
|
567 |
+
$this->save_tracking_items( $order_id, $tracking_items );
|
568 |
+
|
569 |
+
return $tracking_item;
|
570 |
+
}
|
571 |
+
|
572 |
+
/**
|
573 |
+
* Saves the tracking items array to post_meta.
|
574 |
+
*
|
575 |
+
* @param int $order_id Order ID
|
576 |
+
* @param array $tracking_items List of tracking item
|
577 |
+
*/
|
578 |
+
public function save_tracking_items( $order_id, $tracking_items ) {
|
579 |
+
if ( version_compare( WC_VERSION, '3.0', '<' ) ) {
|
580 |
+
update_post_meta( $order_id, '_aftership_tracking_items', $tracking_items );
|
581 |
+
} else {
|
582 |
+
$order = new WC_Order( $order_id );
|
583 |
+
$order->update_meta_data( '_aftership_tracking_items', $tracking_items );
|
584 |
+
$order->save_meta_data();
|
585 |
+
}
|
586 |
+
}
|
587 |
+
|
588 |
+
/**
|
589 |
+
* Gets a single tracking item from the post_meta array for an order.
|
590 |
+
*
|
591 |
+
* @param int $order_id Order ID
|
592 |
+
* @param string $tracking_id Tracking ID
|
593 |
+
*
|
594 |
+
* @return null|array Null if not found, otherwise array of tracking item will be returned
|
595 |
+
*/
|
596 |
+
public function get_tracking_item( $order_id, $tracking_id ) {
|
597 |
+
$tracking_items = $this->get_tracking_items( $order_id );
|
598 |
+
|
599 |
+
if ( count( $tracking_items ) ) {
|
600 |
+
foreach ( $tracking_items as $item ) {
|
601 |
+
if ( $item['tracking_id'] === $tracking_id ) {
|
602 |
+
return $item;
|
603 |
+
}
|
604 |
+
}
|
605 |
+
}
|
606 |
+
|
607 |
+
return null;
|
608 |
+
}
|
609 |
+
|
610 |
+
/*
|
611 |
+
* Gets all tracking items from the post meta array for an order
|
612 |
+
*
|
613 |
+
* @param int $order_id Order ID
|
614 |
+
*
|
615 |
+
* @return array List of tracking items
|
616 |
+
*/
|
617 |
+
public function get_tracking_items( $order_id ) {
|
618 |
+
|
619 |
+
if ( version_compare( WC_VERSION, '3.0', '<' ) ) {
|
620 |
+
$tracking_items = get_post_meta( $order_id, '_aftership_tracking_items', true );
|
621 |
+
} else {
|
622 |
+
$order = new WC_Order( $order_id );
|
623 |
+
$tracking_items = $order->get_meta( '_aftership_tracking_items', true );
|
624 |
+
}
|
625 |
+
|
626 |
+
if ( is_array( $tracking_items ) ) {
|
627 |
+
return $tracking_items;
|
628 |
+
} else {
|
629 |
+
return array();
|
630 |
+
}
|
631 |
+
}
|
632 |
+
|
633 |
+
/*
|
634 |
+
* Gets all tracking items from the post meta array for an order using by restful api
|
635 |
+
*
|
636 |
+
* @param int $order_id Order ID
|
637 |
+
*
|
638 |
+
* @return array List of tracking items
|
639 |
+
*/
|
640 |
+
public function get_tracking_items_for_api( $order_id ) {
|
641 |
+
// migrate old tracking meta
|
642 |
+
$this->convert_old_meta_in_order( $order_id );
|
643 |
+
$tracking_items = $this->get_tracking_items( $order_id );
|
644 |
+
$order = new WC_Order( $order_id );
|
645 |
+
foreach ( $tracking_items as $key => $tracking_item ) {
|
646 |
+
$additional_fields = $tracking_item['additional_fields'];
|
647 |
+
if ( isset( $additional_fields['destination_country'] ) ) {
|
648 |
+
// Use customer's input first
|
649 |
+
if ( $additional_fields['destination_country'] ) {
|
650 |
+
$tracking_item['additional_fields']['destination_country'] = convert_country_code( $additional_fields['destination_country'] );
|
651 |
+
} else {
|
652 |
+
// Use destination_country from shipping address
|
653 |
+
$destination_country = $order->get_shipping_country();
|
654 |
+
if ( ! $destination_country ) {
|
655 |
+
$destination_country = $order->get_billing_country();
|
656 |
+
}
|
657 |
+
$tracking_item['additional_fields']['destination_country'] = convert_country_code( $destination_country );
|
658 |
+
}
|
659 |
+
}
|
660 |
+
if ( isset( $additional_fields['ship_date'] ) ) {
|
661 |
+
if ( $additional_fields['ship_date'] ) {
|
662 |
+
$tracking_item['additional_fields']['ship_date'] = date( 'Ymd', strtotime( $tracking_item['additional_fields']['ship_date'] ) );
|
663 |
+
}
|
664 |
+
}
|
665 |
+
$tracking_items[ $key ] = $tracking_item;
|
666 |
+
}
|
667 |
+
return $tracking_items;
|
668 |
+
}
|
669 |
+
|
670 |
+
/**
|
671 |
+
* Convert old meta in a given order ID to new meta structure.
|
672 |
+
*
|
673 |
+
* @param int $order_id Order ID.
|
674 |
+
*/
|
675 |
+
public function convert_old_meta_in_order( $order_id ) {
|
676 |
+
|
677 |
+
$migrate = get_post_meta( $order_id, '_aftership_migrated', true );
|
678 |
+
if ( $migrate === 'ok' ) {
|
679 |
+
return;
|
680 |
+
}
|
681 |
+
update_post_meta( $order_id, '_aftership_migrated', 'ok' );
|
682 |
+
|
683 |
+
$slug = get_post_meta( $order_id, '_aftership_tracking_provider_name', true );
|
684 |
+
$tracking_number = get_post_meta( $order_id, '_aftership_tracking_number', true );
|
685 |
+
$account_number = get_post_meta( $order_id, '_aftership_tracking_account', true );
|
686 |
+
$key = get_post_meta( $order_id, '_aftership_tracking_key', true );
|
687 |
+
$postal_code = get_post_meta( $order_id, '_aftership_tracking_postal', true );
|
688 |
+
$ship_date = get_post_meta( $order_id, '_aftership_tracking_shipdate', true );
|
689 |
+
$destination_country = get_post_meta( $order_id, '_aftership_tracking_destination_country', true );
|
690 |
+
|
691 |
+
if ( ! $tracking_number ) {
|
692 |
+
return;
|
693 |
+
}
|
694 |
+
|
695 |
+
$args = array(
|
696 |
+
'slug' => $slug,
|
697 |
+
'tracking_number' => $tracking_number,
|
698 |
+
'additional_fields' => array(
|
699 |
+
'account_number' => $account_number,
|
700 |
+
'key' => $key,
|
701 |
+
'postal_code' => $postal_code,
|
702 |
+
'ship_date' => $ship_date,
|
703 |
+
'destination_country' => $destination_country,
|
704 |
+
'state' => '',
|
705 |
+
),
|
706 |
+
);
|
707 |
+
|
708 |
+
$this->add_tracking_item( $order_id, $args );
|
709 |
+
|
710 |
+
}
|
711 |
+
|
712 |
+
/*
|
713 |
+
* Gets all tracking items from the post meta array for an order
|
714 |
+
*
|
715 |
+
* @param int $order_id Order ID
|
716 |
+
*
|
717 |
+
* @return array List of tracking items
|
718 |
+
*/
|
719 |
+
public function get_tracking_items_for_display( $order_id ) {
|
720 |
+
$custom_domain = $GLOBALS['AfterShip']->custom_domain;
|
721 |
+
$tracking_items = $this->get_tracking_items( $order_id );
|
722 |
+
$display_tracking_items = array();
|
723 |
+
foreach ( $tracking_items as $item ) {
|
724 |
+
$display_item = $item;
|
725 |
+
$display_item['courier'] = $this->get_courier_by_slug( $item['slug'] );
|
726 |
+
$display_item['custom_domain'] = $custom_domain;
|
727 |
+
$display_item['tracking_number_for_tracking_button'] = $this->get_tracking_number_for_tracking_button( $item );
|
728 |
+
$display_tracking_items[] = $display_item;
|
729 |
+
}
|
730 |
+
return $display_tracking_items;
|
731 |
+
}
|
732 |
+
|
733 |
+
/**
|
734 |
+
* Map courier required_fields to tracking additional_fields
|
735 |
+
*
|
736 |
+
* @param string $courier_required_field
|
737 |
+
* @return string
|
738 |
+
*/
|
739 |
+
public function mapping_tracking_additional_fields( $courier_required_field ) {
|
740 |
+
|
741 |
+
$mapping = array(
|
742 |
+
'tracking_key' => 'key',
|
743 |
+
'tracking_account_number' => 'account_number',
|
744 |
+
'tracking_postal_code' => 'postal_code',
|
745 |
+
'tracking_ship_date' => 'ship_date',
|
746 |
+
'tracking_destination_country' => 'destination_country',
|
747 |
+
'tracking_state' => 'state',
|
748 |
+
);
|
749 |
+
|
750 |
+
return isset( $mapping[ $courier_required_field ] ) ? $mapping[ $courier_required_field ] : $courier_required_field;
|
751 |
+
}
|
752 |
+
|
753 |
+
|
754 |
+
/**
|
755 |
+
* @param $item array
|
756 |
+
* @param bool $with_additional_fields
|
757 |
+
* @return string
|
758 |
+
* @todo AfterShip tracking button not support additional_fields yet.
|
759 |
+
*/
|
760 |
+
public function get_tracking_number_for_tracking_button( $item, $with_additional_fields = false ) {
|
761 |
+
$tracking_number = $item['tracking_number'];
|
762 |
+
if ( $with_additional_fields ) {
|
763 |
+
$tracking_number_with_additional_fields = $tracking_number;
|
764 |
+
$courier = $this->get_courier_by_slug( $item['slug'] );
|
765 |
+
foreach ( $courier['required_fields'] as $field ) {
|
766 |
+
$additional_field = $this->mapping_tracking_additional_fields( $field );
|
767 |
+
$additional_field_value = isset( $item['additional_fields'][ $additional_field ] ) ? $item['additional_fields'][ $additional_field ] : '';
|
768 |
+
$tracking_number_with_additional_fields .= ':' . $additional_field_value;
|
769 |
+
}
|
770 |
+
return $tracking_number_with_additional_fields;
|
771 |
+
}
|
772 |
+
return $tracking_number;
|
773 |
+
}
|
774 |
+
|
775 |
+
/**
|
776 |
+
* Display the API key info for a user
|
777 |
+
*
|
778 |
+
* @param WP_User $user
|
779 |
+
*/
|
780 |
+
public function add_api_key_field( $user ) {
|
781 |
+
if ( ! current_user_can( 'manage_aftership' ) ) {
|
782 |
+
return;
|
783 |
+
}
|
784 |
+
if ( current_user_can( 'edit_user', $user->ID ) ) {
|
785 |
+
?>
|
786 |
+
<h3>AfterShip</h3>
|
787 |
+
<table class="form-table">
|
788 |
+
<tbody>
|
789 |
+
<tr>
|
790 |
+
<th><label
|
791 |
+
for="aftership_wp_api_key"><?php _e( 'AfterShip\'s WordPress API Key', 'aftership' ); ?></label>
|
792 |
+
</th>
|
793 |
+
<td>
|
794 |
+
<?php if ( empty( $user->aftership_wp_api_key ) ) : ?>
|
795 |
+
<input name="aftership_wp_generate_api_key" type="checkbox"
|
796 |
+
id="aftership_wp_generate_api_key" value="0"/>
|
797 |
+
<span class="description"><?php _e( 'Generate API Key', 'aftership' ); ?></span>
|
798 |
+
<?php else : ?>
|
799 |
+
<code id="aftership_wp_api_key"><?php echo $user->aftership_wp_api_key; ?></code>
|
800 |
+
<br/>
|
801 |
+
<input name="aftership_wp_generate_api_key" type="checkbox"
|
802 |
+
id="aftership_wp_generate_api_key" value="0"/>
|
803 |
+
<span class="description"><?php _e( 'Revoke API Key', 'aftership' ); ?></span>
|
804 |
+
<?php endif; ?>
|
805 |
+
</td>
|
806 |
+
</tr>
|
807 |
+
</tbody>
|
808 |
+
</table>
|
809 |
+
<?php
|
810 |
+
}
|
811 |
+
}
|
812 |
+
|
813 |
+
/**
|
814 |
+
* Generate and save (or delete) the API keys for a user
|
815 |
+
*
|
816 |
+
* @param int $user_id
|
817 |
+
*/
|
818 |
+
public function generate_api_key( $user_id ) {
|
819 |
+
if ( current_user_can( 'edit_user', $user_id ) ) {
|
820 |
+
$user = get_userdata( $user_id );
|
821 |
+
// creating/deleting key
|
822 |
+
if ( isset( $_POST['aftership_wp_generate_api_key'] ) ) {
|
823 |
+
// consumer key
|
824 |
+
if ( empty( $user->aftership_wp_api_key ) ) {
|
825 |
+
$api_key = 'ck_' . hash( 'md5', $user->user_login . date( 'U' ) . mt_rand() );
|
826 |
+
update_user_meta( $user_id, 'aftership_wp_api_key', $api_key );
|
827 |
+
} else {
|
828 |
+
delete_user_meta( $user_id, 'aftership_wp_api_key' );
|
829 |
+
}
|
830 |
+
}
|
831 |
+
}
|
832 |
+
}
|
833 |
+
}
|
includes/class-aftership-settings.php
ADDED
@@ -0,0 +1,187 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* AfterShip Admin
|
4 |
+
*
|
5 |
+
* Handles AfterShip-Admin endpoint requests
|
6 |
+
*
|
7 |
+
* @author AfterShip
|
8 |
+
* @category Admin
|
9 |
+
* @package AfterShip
|
10 |
+
* @since 1.0
|
11 |
+
*/
|
12 |
+
|
13 |
+
if ( ! defined( 'ABSPATH' ) ) {
|
14 |
+
exit; // Exit if accessed directly
|
15 |
+
}
|
16 |
+
|
17 |
+
class AfterShip_Settings {
|
18 |
+
|
19 |
+
/**
|
20 |
+
* Holds the values to be used in the fields callbacks
|
21 |
+
*/
|
22 |
+
private $options;
|
23 |
+
|
24 |
+
/**
|
25 |
+
* Start up
|
26 |
+
*/
|
27 |
+
public function __construct() {
|
28 |
+
add_action( 'admin_menu', array( $this, 'add_plugin_page' ) );
|
29 |
+
add_action( 'admin_init', array( $this, 'page_init' ) );
|
30 |
+
add_action( 'admin_print_styles', array( $this, 'admin_styles' ) );
|
31 |
+
add_action( 'admin_print_scripts', array( &$this, 'library_scripts' ) );
|
32 |
+
}
|
33 |
+
|
34 |
+
|
35 |
+
public function admin_styles() {
|
36 |
+
wp_enqueue_style( 'aftership_styles_chosen', aftership()->plugin_url . '/assets/plugin/chosen/chosen.min.css' );
|
37 |
+
}
|
38 |
+
|
39 |
+
public function library_scripts() {
|
40 |
+
$plugin_url = aftership()->plugin_url;
|
41 |
+
wp_enqueue_script( 'aftership_styles_chosen_jquery', $plugin_url . '/assets/plugin/chosen/chosen.jquery.min.js' );
|
42 |
+
wp_enqueue_script( 'aftership_styles_chosen_proto', $plugin_url . '/assets/plugin/chosen/chosen.proto.min.js' );
|
43 |
+
wp_enqueue_script( 'aftership_script_util', $plugin_url . '/assets/js/util.js' );
|
44 |
+
wp_enqueue_script( 'aftership_script_couriers', $plugin_url . '/assets/js/couriers.js' );
|
45 |
+
wp_enqueue_script( 'aftership_script_setting', $plugin_url . '/assets/js/setting.js' );
|
46 |
+
}
|
47 |
+
|
48 |
+
/**
|
49 |
+
* Add options page
|
50 |
+
*/
|
51 |
+
public function add_plugin_page() {
|
52 |
+
// This page will be under "Settings"
|
53 |
+
add_options_page(
|
54 |
+
'AfterShip Settings Admin',
|
55 |
+
'AfterShip',
|
56 |
+
'manage_options',
|
57 |
+
'aftership-setting-admin',
|
58 |
+
array( $this, 'create_admin_page' )
|
59 |
+
);
|
60 |
+
}
|
61 |
+
|
62 |
+
/**
|
63 |
+
* Options page callback
|
64 |
+
*/
|
65 |
+
public function create_admin_page() {
|
66 |
+
// Set class property
|
67 |
+
$this->options = get_option( 'aftership_option_name' );
|
68 |
+
?>
|
69 |
+
<div class="wrap">
|
70 |
+
<h2>AfterShip Settings</h2>
|
71 |
+
|
72 |
+
<form method="post" action="options.php">
|
73 |
+
<?php
|
74 |
+
// This prints out all hidden setting fields
|
75 |
+
settings_fields( 'aftership_option_group' );
|
76 |
+
do_settings_sections( 'aftership-setting-admin' );
|
77 |
+
submit_button();
|
78 |
+
?>
|
79 |
+
</form>
|
80 |
+
</div>
|
81 |
+
<?php
|
82 |
+
}
|
83 |
+
|
84 |
+
/**
|
85 |
+
* Register and add settings
|
86 |
+
*/
|
87 |
+
public function page_init() {
|
88 |
+
register_setting(
|
89 |
+
'aftership_option_group', // Option group
|
90 |
+
'aftership_option_name', // Option name
|
91 |
+
array( $this, 'sanitize' ) // Sanitize
|
92 |
+
);
|
93 |
+
|
94 |
+
add_settings_section(
|
95 |
+
'aftership_setting_section_id', // ID
|
96 |
+
'', // Title
|
97 |
+
array( $this, 'print_section_info' ), // Callback
|
98 |
+
'aftership-setting-admin' // Page
|
99 |
+
);
|
100 |
+
|
101 |
+
add_settings_field(
|
102 |
+
'couriers',
|
103 |
+
'Couriers',
|
104 |
+
array( $this, 'couriers_callback' ),
|
105 |
+
'aftership-setting-admin',
|
106 |
+
'aftership_setting_section_id'
|
107 |
+
);
|
108 |
+
|
109 |
+
add_settings_field(
|
110 |
+
'use_track_button',
|
111 |
+
'Display Track Button at Order History Page',
|
112 |
+
array( $this, 'track_button_callback' ),
|
113 |
+
'aftership-setting-admin',
|
114 |
+
'aftership_setting_section_id'
|
115 |
+
);
|
116 |
+
|
117 |
+
add_settings_field(
|
118 |
+
'custom_domain',
|
119 |
+
'Display Tracking Information at Custom Domain',
|
120 |
+
array( $this, 'custom_domain_callback' ),
|
121 |
+
'aftership-setting-admin',
|
122 |
+
'aftership_setting_section_id'
|
123 |
+
);
|
124 |
+
}
|
125 |
+
|
126 |
+
/**
|
127 |
+
* Sanitize each setting field as needed
|
128 |
+
*
|
129 |
+
* @param array $input Contains all settings fields as array keys
|
130 |
+
* @return array
|
131 |
+
*/
|
132 |
+
public function sanitize( $input ) {
|
133 |
+
$new_input = array();
|
134 |
+
|
135 |
+
if ( isset( $input['couriers'] ) ) {
|
136 |
+
$new_input['couriers'] = sanitize_text_field( $input['couriers'] );
|
137 |
+
}
|
138 |
+
|
139 |
+
if ( isset( $input['custom_domain'] ) ) {
|
140 |
+
$new_input['custom_domain'] = sanitize_text_field( $input['custom_domain'] );
|
141 |
+
}
|
142 |
+
|
143 |
+
if ( isset( $input['use_track_button'] ) ) {
|
144 |
+
$new_input['use_track_button'] = true;
|
145 |
+
}
|
146 |
+
|
147 |
+
return $new_input;
|
148 |
+
}
|
149 |
+
|
150 |
+
/**
|
151 |
+
* Print the Section text
|
152 |
+
*/
|
153 |
+
public function print_section_info() {
|
154 |
+
// print 'Enter your settings below:';
|
155 |
+
}
|
156 |
+
|
157 |
+
public function couriers_callback() {
|
158 |
+
|
159 |
+
$couriers = array();
|
160 |
+
if ( isset( $this->options['couriers'] ) ) {
|
161 |
+
$couriers = explode( ',', $this->options['couriers'] );
|
162 |
+
}
|
163 |
+
echo '<select data-placeholder="Please select couriers" id="couriers_select" multiple style="width:100%">';
|
164 |
+
echo '</select>';
|
165 |
+
echo '<input type="hidden" id="couriers" name="aftership_option_name[couriers]" value="' . implode( ',', $couriers ) . '"/>';
|
166 |
+
|
167 |
+
}
|
168 |
+
|
169 |
+
public function custom_domain_callback() {
|
170 |
+
printf(
|
171 |
+
'<input type="text" id="custom_domain" name="aftership_option_name[custom_domain]" value="%s" style="width:100%%">',
|
172 |
+
isset( $this->options['custom_domain'] ) ? $this->options['custom_domain'] : 'track.aftership.com'
|
173 |
+
);
|
174 |
+
}
|
175 |
+
|
176 |
+
public function track_button_callback() {
|
177 |
+
printf(
|
178 |
+
'<label><input type="checkbox" id="use_track_button" name="aftership_option_name[use_track_button]" %s>Use Track Button</label>',
|
179 |
+
( isset( $this->options['use_track_button'] ) && $this->options['use_track_button'] === true ) ? 'checked="checked"' : ''
|
180 |
+
);
|
181 |
+
}
|
182 |
+
}
|
183 |
+
|
184 |
+
|
185 |
+
if ( is_admin() ) {
|
186 |
+
$aftership_settings = new AfterShip_Settings();
|
187 |
+
}
|
phpcs.xml
ADDED
@@ -0,0 +1,21 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?xml version="1.0"?>
|
2 |
+
<ruleset name="WordPress Coding Standards for Plugins">
|
3 |
+
<description>Generally-applicable sniffs for WordPress plugins</description>
|
4 |
+
|
5 |
+
<rule ref="WordPress-Core" />
|
6 |
+
<rule ref="WordPress-Docs">
|
7 |
+
<exclude name="Squiz.Commenting.FunctionCommentThrowTag.Missing" />
|
8 |
+
<exclude name="Squiz.Commenting.LongConditionClosingComment.Missing" />
|
9 |
+
<exclude name="WordPress.NamingConventions.ValidVariableName.NotSnakeCaseMemberVar" />
|
10 |
+
<exclude name="WordPress.NamingConventions.ValidFunctionName.FunctionNameInvalid" />
|
11 |
+
<exclude name="WordPress.Files.FileName.InvalidClassFileName" />
|
12 |
+
</rule>
|
13 |
+
|
14 |
+
<exclude-pattern>/lib/*</exclude-pattern>
|
15 |
+
<exclude-pattern>/woo-includes/*</exclude-pattern>
|
16 |
+
<exclude-pattern>/tests/*</exclude-pattern>
|
17 |
+
<exclude-pattern>*/node_modules/*</exclude-pattern>
|
18 |
+
<exclude-pattern>*/vendor/*</exclude-pattern>
|
19 |
+
<exclude-pattern>*.js</exclude-pattern>
|
20 |
+
<exclude-pattern>*.css</exclude-pattern>
|
21 |
+
</ruleset>
|
readme.txt
CHANGED
@@ -4,7 +4,7 @@ Donate link: https://www.aftership.com/
|
|
4 |
Tags: ecommerce, shipping, shipment, order, ups, usps, fedex, dhl, tnt, dpd, post, carrier, courier, woocommerce, tracking number, aftership, package tracking, woo commerce, woocommerce shipment tracking, shipping details plugin, widget, shipstation, track, package
|
5 |
Requires at least: 2.9
|
6 |
Tested up to: 5.6
|
7 |
-
Stable tag: 1.
|
8 |
License: GPLv2 or later
|
9 |
License URI: http://www.gnu.org/licenses/gpl-2.0.html
|
10 |
|
@@ -95,9 +95,8 @@ You'll find the FAQ on [AfterShip.com](https://aftership.uservoice.com/knowledge
|
|
95 |
|
96 |
== Changelog ==
|
97 |
|
98 |
-
|
99 |
-
|
100 |
-
* Update courier name for australia-post-api
|
101 |
|
102 |
= 1.10.3 =
|
103 |
* Update readme
|
4 |
Tags: ecommerce, shipping, shipment, order, ups, usps, fedex, dhl, tnt, dpd, post, carrier, courier, woocommerce, tracking number, aftership, package tracking, woo commerce, woocommerce shipment tracking, shipping details plugin, widget, shipstation, track, package
|
5 |
Requires at least: 2.9
|
6 |
Tested up to: 5.6
|
7 |
+
Stable tag: 1.11.0
|
8 |
License: GPLv2 or later
|
9 |
License URI: http://www.gnu.org/licenses/gpl-2.0.html
|
10 |
|
95 |
|
96 |
== Changelog ==
|
97 |
|
98 |
+
= 1.11.0 =
|
99 |
+
* Support Multiple Tracking Number
|
|
|
100 |
|
101 |
= 1.10.3 =
|
102 |
* Update readme
|
templates/email/plain/tracking-info.php
ADDED
@@ -0,0 +1,30 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
if ( ! defined( 'ABSPATH' ) ) {
|
3 |
+
exit;
|
4 |
+
}
|
5 |
+
|
6 |
+
/**
|
7 |
+
* AfterShip
|
8 |
+
*
|
9 |
+
* Shows tracking information in the plain text order email
|
10 |
+
*
|
11 |
+
* @author AfterShip
|
12 |
+
* @package AfterShip Tracking/templates/email
|
13 |
+
*/
|
14 |
+
|
15 |
+
if ( $tracking_items ) :
|
16 |
+
|
17 |
+
echo apply_filters( 'aftership_tracking_my_orders_title', __( 'TRACKING INFORMATION', 'aftership' ) );
|
18 |
+
|
19 |
+
echo "\n";
|
20 |
+
|
21 |
+
foreach ( $tracking_items as $tracking_item ) {
|
22 |
+
echo esc_html( $tracking_item['courier']['name'] ) . "\n";
|
23 |
+
echo esc_html( $tracking_item['tracking_number'] ) . "\n";
|
24 |
+
}
|
25 |
+
|
26 |
+
echo "=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= \n\n";
|
27 |
+
|
28 |
+
endif;
|
29 |
+
|
30 |
+
|
templates/email/tracking-info.php
ADDED
@@ -0,0 +1,44 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
if ( ! defined( 'ABSPATH' ) ) {
|
3 |
+
exit;
|
4 |
+
}
|
5 |
+
|
6 |
+
/**
|
7 |
+
* View Order: Tracking information
|
8 |
+
*
|
9 |
+
* Shows tracking numbers view order page
|
10 |
+
*
|
11 |
+
* @author AfterShip
|
12 |
+
* @package AfterShip Tracking/templates/email
|
13 |
+
*/
|
14 |
+
|
15 |
+
if ( $tracking_items ) : ?>
|
16 |
+
<h2><?php echo apply_filters( 'aftership_tracking_my_orders_title', __( 'Tracking Information', 'aftership' ) ); ?></h2>
|
17 |
+
|
18 |
+
<table class="td" cellspacing="0" cellpadding="6" style="width: 100%;" border="1">
|
19 |
+
<thead>
|
20 |
+
<tr>
|
21 |
+
<th class="slug" scope="col" class="td" style="text-align: left; font-family: 'Helvetica Neue', Helvetica, Roboto, Arial, sans-serif; color: #737373; border: 1px solid #e4e4e4; padding: 12px;"><?php _e( 'Courier', 'aftership' ); ?></th>
|
22 |
+
<th class="tracking-number" scope="col" class="td" style="text-align: left; font-family: 'Helvetica Neue', Helvetica, Roboto, Arial, sans-serif; color: #737373; border: 1px solid #e4e4e4; padding: 12px;"><?php _e( 'Tracking Number', 'aftership' ); ?></th>
|
23 |
+
</tr>
|
24 |
+
</thead>
|
25 |
+
<tbody>
|
26 |
+
<?php
|
27 |
+
foreach ( $tracking_items as $tracking_item ) {
|
28 |
+
?>
|
29 |
+
<tr class="tracking">
|
30 |
+
<td class="slug" data-title="<?php _e( 'Courier', 'aftership' ); ?>" style="text-align: left; font-family: 'Helvetica Neue', Helvetica, Roboto, Arial, sans-serif; color: #737373; border: 1px solid #e4e4e4; padding: 12px;">
|
31 |
+
<?php echo esc_html( $tracking_item['courier']['name'] ); ?>
|
32 |
+
</td>
|
33 |
+
<td class="tracking-number" data-title="<?php _e( 'Tracking Number', 'aftership' ); ?>" style="text-align: left; font-family: 'Helvetica Neue', Helvetica, Roboto, Arial, sans-serif; color: #737373; border: 1px solid #e4e4e4; padding: 12px;">
|
34 |
+
<?php echo esc_html( $tracking_item['tracking_number'] ); ?>
|
35 |
+
</td>
|
36 |
+
</tr>
|
37 |
+
<?php
|
38 |
+
}
|
39 |
+
?>
|
40 |
+
</tbody>
|
41 |
+
</table>
|
42 |
+
|
43 |
+
<?php
|
44 |
+
endif;
|
templates/myaccount/view-order.php
ADDED
@@ -0,0 +1,54 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
if ( ! defined( 'ABSPATH' ) ) {
|
3 |
+
exit;
|
4 |
+
}
|
5 |
+
|
6 |
+
/**
|
7 |
+
* View Order: Tracking information
|
8 |
+
*
|
9 |
+
* Shows tracking numbers view order page
|
10 |
+
*
|
11 |
+
* @author AfterShip
|
12 |
+
* @package AfterShip Tracking/templates/myaccount
|
13 |
+
*/
|
14 |
+
|
15 |
+
if ( $tracking_items ) : ?>
|
16 |
+
<div id="as-root"></div><script>(function(e,t,n){var r,i=e.getElementsByTagName(t)[0];if(e.getElementById(n))return;r=e.createElement(t);r.id=n;r.src="https://button.aftership.com/all.js";i.parentNode.insertBefore(r,i)})(document,"script","aftership-jssdk")</script>
|
17 |
+
<h2><?php echo apply_filters( 'aftership_tracking_my_orders_title', __( 'Tracking Information', 'aftership' ) ); ?></h2>
|
18 |
+
|
19 |
+
<table class="shop_table shop_table_responsive my_account_tracking">
|
20 |
+
<thead>
|
21 |
+
<tr>
|
22 |
+
<th class="slug"><span class="nobr"><?php _e( 'Courier', 'aftership' ); ?></span></th>
|
23 |
+
<th class="tracking-number"><span class="nobr"><?php _e( 'Tracking Number', 'aftership' ); ?></span></th>
|
24 |
+
<?php if ( $use_track_button ) { ?>
|
25 |
+
<th class="order-actions"><?php _e( 'Actions', 'aftership' ); ?></th>
|
26 |
+
<?php } ?>
|
27 |
+
|
28 |
+
</tr>
|
29 |
+
</thead>
|
30 |
+
<tbody>
|
31 |
+
<?php
|
32 |
+
foreach ( $tracking_items as $tracking_item ) {
|
33 |
+
?>
|
34 |
+
<tr class="tracking">
|
35 |
+
<td class="slug" data-title="<?php _e( 'Courier', 'aftership' ); ?>">
|
36 |
+
<?php echo esc_html( $tracking_item['courier']['name'] ); ?>
|
37 |
+
</td>
|
38 |
+
<td class="tracking-number" data-title="<?php _e( 'Tracking Number', 'aftership' ); ?>">
|
39 |
+
<?php echo esc_html( $tracking_item['tracking_number'] ); ?>
|
40 |
+
</td>
|
41 |
+
<?php if ( $use_track_button ) { ?>
|
42 |
+
<td class="order-actions" style="text-align: center;">
|
43 |
+
<div class="as-track-button" data-slug="<?php echo esc_html( $tracking_item['slug'] ); ?>" data-domain="<?php echo esc_html( $tracking_item['custom_domain'] ); ?>" data-tracking-number="<?php echo esc_html( $tracking_item['tracking_number_for_tracking_button'] ); ?>" data-size="normal" data-hide-tracking-number="true"></div>
|
44 |
+
</td>
|
45 |
+
<?php } ?>
|
46 |
+
</tr>
|
47 |
+
<?php
|
48 |
+
}
|
49 |
+
?>
|
50 |
+
</tbody>
|
51 |
+
</table>
|
52 |
+
|
53 |
+
<?php
|
54 |
+
endif;
|
woo-includes/class-wc-dependencies.php
ADDED
@@ -0,0 +1,28 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* WC Dependency Checker
|
4 |
+
*
|
5 |
+
* Checks if WooCommerce is enabled
|
6 |
+
*/
|
7 |
+
class WC_Dependencies {
|
8 |
+
|
9 |
+
private static $active_plugins;
|
10 |
+
|
11 |
+
public static function init() {
|
12 |
+
|
13 |
+
self::$active_plugins = (array) get_option( 'active_plugins', array() );
|
14 |
+
|
15 |
+
if ( is_multisite() )
|
16 |
+
self::$active_plugins = array_merge( self::$active_plugins, get_site_option( 'active_sitewide_plugins', array() ) );
|
17 |
+
}
|
18 |
+
|
19 |
+
public static function woocommerce_active_check() {
|
20 |
+
|
21 |
+
if ( ! self::$active_plugins ) self::init();
|
22 |
+
|
23 |
+
return in_array( 'woocommerce/woocommerce.php', self::$active_plugins ) || array_key_exists( 'woocommerce/woocommerce.php', self::$active_plugins );
|
24 |
+
}
|
25 |
+
|
26 |
+
}
|
27 |
+
|
28 |
+
|
woo-includes/woo-functions.php
ADDED
@@ -0,0 +1,295 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Functions used by plugins
|
4 |
+
*/
|
5 |
+
if ( ! class_exists( 'WC_Dependencies' ) )
|
6 |
+
require_once 'class-wc-dependencies.php';
|
7 |
+
|
8 |
+
/**
|
9 |
+
* WC Detection
|
10 |
+
*/
|
11 |
+
if ( ! function_exists( 'is_woocommerce_active' ) ) {
|
12 |
+
function is_woocommerce_active() {
|
13 |
+
return WC_Dependencies::woocommerce_active_check();
|
14 |
+
}
|
15 |
+
}
|
16 |
+
|
17 |
+
if ( ! function_exists( 'get_order_id' ) ) {
|
18 |
+
function get_order_id($order) {
|
19 |
+
return (method_exists($order, 'get_id'))? $order->get_id() : $order->id;
|
20 |
+
}
|
21 |
+
}
|
22 |
+
|
23 |
+
if ( ! function_exists( 'order_post_meta_getter' ) ) {
|
24 |
+
function order_post_meta_getter($order, $attr) {
|
25 |
+
$meta = get_post_meta(get_order_id($order), '_'. $attr, true);
|
26 |
+
return $meta;
|
27 |
+
}
|
28 |
+
}
|
29 |
+
|
30 |
+
if ( ! function_exists( 'convert_country_code' ) ) {
|
31 |
+
/**
|
32 |
+
* Converts the WooCommerce country codes to 3-letter ISO codes
|
33 |
+
* https://en.wikipedia.org/wiki/ISO_3166-1_alpha-3
|
34 |
+
*
|
35 |
+
* @param string WooCommerce's 2 letter country code
|
36 |
+
* @return string ISO 3-letter country code
|
37 |
+
*/
|
38 |
+
function convert_country_code($country)
|
39 |
+
{
|
40 |
+
$countries = array(
|
41 |
+
'AF' => 'AFG', // Afghanistan
|
42 |
+
'AX' => 'ALA', // Åland Islands
|
43 |
+
'AL' => 'ALB', // Albania
|
44 |
+
'DZ' => 'DZA', // Algeria
|
45 |
+
'AS' => 'ASM', // American Samoa
|
46 |
+
'AD' => 'AND', // Andorra
|
47 |
+
'AO' => 'AGO', // Angola
|
48 |
+
'AI' => 'AIA', // Anguilla
|
49 |
+
'AQ' => 'ATA', // Antarctica
|
50 |
+
'AG' => 'ATG', // Antigua and Barbuda
|
51 |
+
'AR' => 'ARG', // Argentina
|
52 |
+
'AM' => 'ARM', // Armenia
|
53 |
+
'AW' => 'ABW', // Aruba
|
54 |
+
'AU' => 'AUS', // Australia
|
55 |
+
'AT' => 'AUT', // Austria
|
56 |
+
'AZ' => 'AZE', // Azerbaijan
|
57 |
+
'BS' => 'BHS', // Bahamas
|
58 |
+
'BH' => 'BHR', // Bahrain
|
59 |
+
'BD' => 'BGD', // Bangladesh
|
60 |
+
'BB' => 'BRB', // Barbados
|
61 |
+
'BY' => 'BLR', // Belarus
|
62 |
+
'BE' => 'BEL', // Belgium
|
63 |
+
'BZ' => 'BLZ', // Belize
|
64 |
+
'BJ' => 'BEN', // Benin
|
65 |
+
'BM' => 'BMU', // Bermuda
|
66 |
+
'BT' => 'BTN', // Bhutan
|
67 |
+
'BO' => 'BOL', // Bolivia
|
68 |
+
'BQ' => 'BES', // Bonaire, Saint Estatius and Saba
|
69 |
+
'BA' => 'BIH', // Bosnia and Herzegovina
|
70 |
+
'BW' => 'BWA', // Botswana
|
71 |
+
'BV' => 'BVT', // Bouvet Islands
|
72 |
+
'BR' => 'BRA', // Brazil
|
73 |
+
'IO' => 'IOT', // British Indian Ocean Territory
|
74 |
+
'BN' => 'BRN', // Brunei
|
75 |
+
'BG' => 'BGR', // Bulgaria
|
76 |
+
'BF' => 'BFA', // Burkina Faso
|
77 |
+
'BI' => 'BDI', // Burundi
|
78 |
+
'KH' => 'KHM', // Cambodia
|
79 |
+
'CM' => 'CMR', // Cameroon
|
80 |
+
'CA' => 'CAN', // Canada
|
81 |
+
'CV' => 'CPV', // Cape Verde
|
82 |
+
'KY' => 'CYM', // Cayman Islands
|
83 |
+
'CF' => 'CAF', // Central African Republic
|
84 |
+
'TD' => 'TCD', // Chad
|
85 |
+
'CL' => 'CHL', // Chile
|
86 |
+
'CN' => 'CHN', // China
|
87 |
+
'CX' => 'CXR', // Christmas Island
|
88 |
+
'CC' => 'CCK', // Cocos (Keeling) Islands
|
89 |
+
'CO' => 'COL', // Colombia
|
90 |
+
'KM' => 'COM', // Comoros
|
91 |
+
'CG' => 'COG', // Congo
|
92 |
+
'CD' => 'COD', // Congo, Democratic Republic of the
|
93 |
+
'CK' => 'COK', // Cook Islands
|
94 |
+
'CR' => 'CRI', // Costa Rica
|
95 |
+
'CI' => 'CIV', // Côte d\'Ivoire
|
96 |
+
'HR' => 'HRV', // Croatia
|
97 |
+
'CU' => 'CUB', // Cuba
|
98 |
+
'CW' => 'CUW', // Curaçao
|
99 |
+
'CY' => 'CYP', // Cyprus
|
100 |
+
'CZ' => 'CZE', // Czech Republic
|
101 |
+
'DK' => 'DNK', // Denmark
|
102 |
+
'DJ' => 'DJI', // Djibouti
|
103 |
+
'DM' => 'DMA', // Dominica
|
104 |
+
'DO' => 'DOM', // Dominican Republic
|
105 |
+
'EC' => 'ECU', // Ecuador
|
106 |
+
'EG' => 'EGY', // Egypt
|
107 |
+
'SV' => 'SLV', // El Salvador
|
108 |
+
'GQ' => 'GNQ', // Equatorial Guinea
|
109 |
+
'ER' => 'ERI', // Eritrea
|
110 |
+
'EE' => 'EST', // Estonia
|
111 |
+
'ET' => 'ETH', // Ethiopia
|
112 |
+
'FK' => 'FLK', // Falkland Islands
|
113 |
+
'FO' => 'FRO', // Faroe Islands
|
114 |
+
'FJ' => 'FIJ', // Fiji
|
115 |
+
'FI' => 'FIN', // Finland
|
116 |
+
'FR' => 'FRA', // France
|
117 |
+
'GF' => 'GUF', // French Guiana
|
118 |
+
'PF' => 'PYF', // French Polynesia
|
119 |
+
'TF' => 'ATF', // French Southern Territories
|
120 |
+
'GA' => 'GAB', // Gabon
|
121 |
+
'GM' => 'GMB', // Gambia
|
122 |
+
'GE' => 'GEO', // Georgia
|
123 |
+
'DE' => 'DEU', // Germany
|
124 |
+
'GH' => 'GHA', // Ghana
|
125 |
+
'GI' => 'GIB', // Gibraltar
|
126 |
+
'GR' => 'GRC', // Greece
|
127 |
+
'GL' => 'GRL', // Greenland
|
128 |
+
'GD' => 'GRD', // Grenada
|
129 |
+
'GP' => 'GLP', // Guadeloupe
|
130 |
+
'GU' => 'GUM', // Guam
|
131 |
+
'GT' => 'GTM', // Guatemala
|
132 |
+
'GG' => 'GGY', // Guernsey
|
133 |
+
'GN' => 'GIN', // Guinea
|
134 |
+
'GW' => 'GNB', // Guinea-Bissau
|
135 |
+
'GY' => 'GUY', // Guyana
|
136 |
+
'HT' => 'HTI', // Haiti
|
137 |
+
'HM' => 'HMD', // Heard Island and McDonald Islands
|
138 |
+
'VA' => 'VAT', // Holy See (Vatican City State)
|
139 |
+
'HN' => 'HND', // Honduras
|
140 |
+
'HK' => 'HKG', // Hong Kong
|
141 |
+
'HU' => 'HUN', // Hungary
|
142 |
+
'IS' => 'ISL', // Iceland
|
143 |
+
'IN' => 'IND', // India
|
144 |
+
'ID' => 'IDN', // Indonesia
|
145 |
+
'IR' => 'IRN', // Iran
|
146 |
+
'IQ' => 'IRQ', // Iraq
|
147 |
+
'IE' => 'IRL', // Republic of Ireland
|
148 |
+
'IM' => 'IMN', // Isle of Man
|
149 |
+
'IL' => 'ISR', // Israel
|
150 |
+
'IT' => 'ITA', // Italy
|
151 |
+
'JM' => 'JAM', // Jamaica
|
152 |
+
'JP' => 'JPN', // Japan
|
153 |
+
'JE' => 'JEY', // Jersey
|
154 |
+
'JO' => 'JOR', // Jordan
|
155 |
+
'KZ' => 'KAZ', // Kazakhstan
|
156 |
+
'KE' => 'KEN', // Kenya
|
157 |
+
'KI' => 'KIR', // Kiribati
|
158 |
+
'KP' => 'PRK', // Korea, Democratic People\'s Republic of
|
159 |
+
'KR' => 'KOR', // Korea, Republic of (South)
|
160 |
+
'KW' => 'KWT', // Kuwait
|
161 |
+
'KG' => 'KGZ', // Kyrgyzstan
|
162 |
+
'LA' => 'LAO', // Laos
|
163 |
+
'LV' => 'LVA', // Latvia
|
164 |
+
'LB' => 'LBN', // Lebanon
|
165 |
+
'LS' => 'LSO', // Lesotho
|
166 |
+
'LR' => 'LBR', // Liberia
|
167 |
+
'LY' => 'LBY', // Libya
|
168 |
+
'LI' => 'LIE', // Liechtenstein
|
169 |
+
'LT' => 'LTU', // Lithuania
|
170 |
+
'LU' => 'LUX', // Luxembourg
|
171 |
+
'MO' => 'MAC', // Macao S.A.R., China
|
172 |
+
'MK' => 'MKD', // Macedonia
|
173 |
+
'MG' => 'MDG', // Madagascar
|
174 |
+
'MW' => 'MWI', // Malawi
|
175 |
+
'MY' => 'MYS', // Malaysia
|
176 |
+
'MV' => 'MDV', // Maldives
|
177 |
+
'ML' => 'MLI', // Mali
|
178 |
+
'MT' => 'MLT', // Malta
|
179 |
+
'MH' => 'MHL', // Marshall Islands
|
180 |
+
'MQ' => 'MTQ', // Martinique
|
181 |
+
'MR' => 'MRT', // Mauritania
|
182 |
+
'MU' => 'MUS', // Mauritius
|
183 |
+
'YT' => 'MYT', // Mayotte
|
184 |
+
'MX' => 'MEX', // Mexico
|
185 |
+
'FM' => 'FSM', // Micronesia
|
186 |
+
'MD' => 'MDA', // Moldova
|
187 |
+
'MC' => 'MCO', // Monaco
|
188 |
+
'MN' => 'MNG', // Mongolia
|
189 |
+
'ME' => 'MNE', // Montenegro
|
190 |
+
'MS' => 'MSR', // Montserrat
|
191 |
+
'MA' => 'MAR', // Morocco
|
192 |
+
'MZ' => 'MOZ', // Mozambique
|
193 |
+
'MM' => 'MMR', // Myanmar
|
194 |
+
'NA' => 'NAM', // Namibia
|
195 |
+
'NR' => 'NRU', // Nauru
|
196 |
+
'NP' => 'NPL', // Nepal
|
197 |
+
'NL' => 'NLD', // Netherlands
|
198 |
+
'AN' => 'ANT', // Netherlands Antilles
|
199 |
+
'NC' => 'NCL', // New Caledonia
|
200 |
+
'NZ' => 'NZL', // New Zealand
|
201 |
+
'NI' => 'NIC', // Nicaragua
|
202 |
+
'NE' => 'NER', // Niger
|
203 |
+
'NG' => 'NGA', // Nigeria
|
204 |
+
'NU' => 'NIU', // Niue
|
205 |
+
'NF' => 'NFK', // Norfolk Island
|
206 |
+
'MP' => 'MNP', // Northern Mariana Islands
|
207 |
+
'NO' => 'NOR', // Norway
|
208 |
+
'OM' => 'OMN', // Oman
|
209 |
+
'PK' => 'PAK', // Pakistan
|
210 |
+
'PW' => 'PLW', // Palau
|
211 |
+
'PS' => 'PSE', // Palestinian Territory
|
212 |
+
'PA' => 'PAN', // Panama
|
213 |
+
'PG' => 'PNG', // Papua New Guinea
|
214 |
+
'PY' => 'PRY', // Paraguay
|
215 |
+
'PE' => 'PER', // Peru
|
216 |
+
'PH' => 'PHL', // Philippines
|
217 |
+
'PN' => 'PCN', // Pitcairn
|
218 |
+
'PL' => 'POL', // Poland
|
219 |
+
'PT' => 'PRT', // Portugal
|
220 |
+
'PR' => 'PRI', // Puerto Rico
|
221 |
+
'QA' => 'QAT', // Qatar
|
222 |
+
'RE' => 'REU', // Reunion
|
223 |
+
'RO' => 'ROU', // Romania
|
224 |
+
'RU' => 'RUS', // Russia
|
225 |
+
'RW' => 'RWA', // Rwanda
|
226 |
+
'BL' => 'BLM', // Saint Barthélemy
|
227 |
+
'SH' => 'SHN', // Saint Helena
|
228 |
+
'KN' => 'KNA', // Saint Kitts and Nevis
|
229 |
+
'LC' => 'LCA', // Saint Lucia
|
230 |
+
'MF' => 'MAF', // Saint Martin (French part)
|
231 |
+
'SX' => 'SXM', // Sint Maarten / Saint Matin (Dutch part)
|
232 |
+
'PM' => 'SPM', // Saint Pierre and Miquelon
|
233 |
+
'VC' => 'VCT', // Saint Vincent and the Grenadines
|
234 |
+
'WS' => 'WSM', // Samoa
|
235 |
+
'SM' => 'SMR', // San Marino
|
236 |
+
'ST' => 'STP', // São Tomé and Príncipe
|
237 |
+
'SA' => 'SAU', // Saudi Arabia
|
238 |
+
'SN' => 'SEN', // Senegal
|
239 |
+
'RS' => 'SRB', // Serbia
|
240 |
+
'SC' => 'SYC', // Seychelles
|
241 |
+
'SL' => 'SLE', // Sierra Leone
|
242 |
+
'SG' => 'SGP', // Singapore
|
243 |
+
'SK' => 'SVK', // Slovakia
|
244 |
+
'SI' => 'SVN', // Slovenia
|
245 |
+
'SB' => 'SLB', // Solomon Islands
|
246 |
+
'SO' => 'SOM', // Somalia
|
247 |
+
'ZA' => 'ZAF', // South Africa
|
248 |
+
'GS' => 'SGS', // South Georgia/Sandwich Islands
|
249 |
+
'SS' => 'SSD', // South Sudan
|
250 |
+
'ES' => 'ESP', // Spain
|
251 |
+
'LK' => 'LKA', // Sri Lanka
|
252 |
+
'SD' => 'SDN', // Sudan
|
253 |
+
'SR' => 'SUR', // Suriname
|
254 |
+
'SJ' => 'SJM', // Svalbard and Jan Mayen
|
255 |
+
'SZ' => 'SWZ', // Swaziland
|
256 |
+
'SE' => 'SWE', // Sweden
|
257 |
+
'CH' => 'CHE', // Switzerland
|
258 |
+
'SY' => 'SYR', // Syria
|
259 |
+
'TW' => 'TWN', // Taiwan
|
260 |
+
'TJ' => 'TJK', // Tajikistan
|
261 |
+
'TZ' => 'TZA', // Tanzania
|
262 |
+
'TH' => 'THA', // Thailand
|
263 |
+
'TL' => 'TLS', // Timor-Leste
|
264 |
+
'TG' => 'TGO', // Togo
|
265 |
+
'TK' => 'TKL', // Tokelau
|
266 |
+
'TO' => 'TON', // Tonga
|
267 |
+
'TT' => 'TTO', // Trinidad and Tobago
|
268 |
+
'TN' => 'TUN', // Tunisia
|
269 |
+
'TR' => 'TUR', // Turkey
|
270 |
+
'TM' => 'TKM', // Turkmenistan
|
271 |
+
'TC' => 'TCA', // Turks and Caicos Islands
|
272 |
+
'TV' => 'TUV', // Tuvalu
|
273 |
+
'UG' => 'UGA', // Uganda
|
274 |
+
'UA' => 'UKR', // Ukraine
|
275 |
+
'AE' => 'ARE', // United Arab Emirates
|
276 |
+
'GB' => 'GBR', // United Kingdom
|
277 |
+
'US' => 'USA', // United States
|
278 |
+
'UM' => 'UMI', // United States Minor Outlying Islands
|
279 |
+
'UY' => 'URY', // Uruguay
|
280 |
+
'UZ' => 'UZB', // Uzbekistan
|
281 |
+
'VU' => 'VUT', // Vanuatu
|
282 |
+
'VE' => 'VEN', // Venezuela
|
283 |
+
'VN' => 'VNM', // Vietnam
|
284 |
+
'VG' => 'VGB', // Virgin Islands, British
|
285 |
+
'VI' => 'VIR', // Virgin Island, U.S.
|
286 |
+
'WF' => 'WLF', // Wallis and Futuna
|
287 |
+
'EH' => 'ESH', // Western Sahara
|
288 |
+
'YE' => 'YEM', // Yemen
|
289 |
+
'ZM' => 'ZMB', // Zambia
|
290 |
+
'ZW' => 'ZWE', // Zimbabwe
|
291 |
+
);
|
292 |
+
$iso_code = isset($countries[$country]) ? $countries[$country] : $country;
|
293 |
+
return $iso_code;
|
294 |
+
}
|
295 |
+
}
|