| 1 |
<?php |
| 2 |
|
| 3 |
use MyParcelNL\Sdk\src\Adapter\DeliveryOptions\AbstractDeliveryOptionsAdapter as DeliveryOptions; |
| 4 |
use MyParcelNL\Sdk\src\Factory\DeliveryOptionsAdapterFactory; |
| 5 |
use MyParcelNL\Sdk\src\Model\Consignment\AbstractConsignment; |
| 6 |
use WPO\WC\PostNL\Compatibility\Order as WCX_Order; |
| 7 |
use WPO\WC\PostNL\Compatibility\Product as WCX_Product; |
| 8 |
use WPO\WC\PostNL\Compatibility\WC_Core as WCX; |
| 9 |
use WPO\WC\PostNL\Entity\SettingsFieldArguments; |
| 10 |
|
| 11 |
if (! defined('ABSPATH')) { |
| 12 |
exit; |
| 13 |
} // Exit if accessed directly |
| 14 |
|
| 15 |
if (class_exists('WCPOST_Admin')) { |
| 16 |
return new WCPOST_Admin(); |
| 17 |
} |
| 18 |
|
| 19 |
/** |
| 20 |
* Admin options, buttons & data |
| 21 |
*/ |
| 22 |
class WCPOST_Admin |
| 23 |
{ |
| 24 |
public const META_CONSIGNMENTS = "_postnl_consignments"; |
| 25 |
public const META_CONSIGNMENT_ID = "_postnl_consignment_id"; |
| 26 |
public const META_DELIVERY_OPTIONS = "_postnl_delivery_options"; |
| 27 |
public const META_HIGHEST_SHIPPING_CLASS = "_postnl_highest_shipping_class"; |
| 28 |
public const META_LAST_SHIPMENT_IDS = "_postnl_last_shipment_ids"; |
| 29 |
public const META_ORDER_VERSION = "_postnl_order_version"; |
| 30 |
public const META_ORDER_WEIGHT = "_postnl_order_weight"; |
| 31 |
public const META_PGADDRESS = "_postnl_pgaddress"; |
| 32 |
public const META_SHIPMENTS = "_postnl_shipments"; |
| 33 |
public const META_SHIPMENT_OPTIONS_EXTRA = "_postnl_shipment_options_extra"; |
| 34 |
public const META_TRACK_TRACE = "_postnl_tracktrace"; |
| 35 |
public const META_HS_CODE = "_postnl_hs_code"; |
| 36 |
public const META_HS_CODE_VARIATION = "_postnl_hs_code_variation"; |
| 37 |
public const META_COUNTRY_OF_ORIGIN = "_postnl_country_of_origin"; |
| 38 |
public const META_ORDER_TOTAL = "_order_version"; |
| 39 |
|
| 40 |
/** |
| 41 |
* Legacy meta keys. |
| 42 |
*/ |
| 43 |
public const META_SHIPMENT_OPTIONS_LT_4_0_0 = "_postnl_shipment_options"; |
| 44 |
|
| 45 |
// Ids referring to shipment statuses. |
| 46 |
public const ORDER_STATUS_DELIVERED_AT_RECIPIENT = 7; |
| 47 |
public const ORDER_STATUS_DELIVERED_READY_FOR_PICKUP = 8; |
| 48 |
public const ORDER_STATUS_DELIVERED_PACKAGE_PICKED_UP = 9; |
| 49 |
|
| 50 |
public const SHIPMENT_OPTIONS_FORM_NAME = "postnl_options"; |
| 51 |
|
| 52 |
public const BULK_ACTION_EXPORT = "wcpn_export"; |
| 53 |
public const BULK_ACTION_PRINT = "wcpn_print"; |
| 54 |
public const BULK_ACTION_EXPORT_PRINT = "wcpn_export_print"; |
| 55 |
|
| 56 |
public function __construct() |
| 57 |
{ |
| 58 |
if (is_wp_version_compatible("4.7.0")) { |
| 59 |
add_action("bulk_actions-edit-shop_order", [$this, "addBulkActions"], 100); |
| 60 |
} else { |
| 61 |
add_action("admin_footer", [$this, "bulk_actions"]); |
| 62 |
} |
| 63 |
|
| 64 |
add_action("admin_footer", [$this, "renderOffsetDialog"]); |
| 65 |
add_action("admin_footer", [$this, "renderShipmentOptionsForm"]); |
| 66 |
|
| 67 |
/** |
| 68 |
* Orders page |
| 69 |
* -- |
| 70 |
* showPostNLSettings is on the woocommerce_admin_order_actions_end hook because there is no hook to put it |
| 71 |
* in the shipping address column... It is put in the right place after loading using JavaScript. |
| 72 |
* |
| 73 |
* @see wcpn-admin.js -> runTriggers() |
| 74 |
*/ |
| 75 |
add_action("woocommerce_admin_order_actions_end", [$this, "showPostNLSettings"], 9999); |
| 76 |
add_action("woocommerce_admin_order_actions_end", [$this, "showOrderActions"], 20); |
| 77 |
|
| 78 |
/* |
| 79 |
* Single order page |
| 80 |
*/ |
| 81 |
add_action("add_meta_boxes_shop_order", [$this, "add_order_meta_box"]); |
| 82 |
add_action("woocommerce_admin_order_data_after_shipping_address", [$this, "single_order_shipment_options"]); |
| 83 |
|
| 84 |
add_action("wp_ajax_wcpn_save_shipment_options", [$this, "save_shipment_options_ajax"]); |
| 85 |
add_action("wp_ajax_wcpn_get_shipment_summary_status", [$this, "order_list_ajax_get_shipment_summary"]); |
| 86 |
add_action("wp_ajax_wcpn_get_shipment_options", [$this, "ajaxGetShipmentOptions"]); |
| 87 |
|
| 88 |
// HS code in product shipping options tab |
| 89 |
add_action("woocommerce_product_options_shipping", [$this, "productHsCodeField"]); |
| 90 |
add_action("woocommerce_process_product_meta", [$this, "productHsCodeFieldSave"]); |
| 91 |
|
| 92 |
// Country of Origin in product shipping options tab |
| 93 |
add_action("woocommerce_product_options_shipping", [$this, "productCountryOfOriginField"]); |
| 94 |
add_action("woocommerce_process_product_meta", [$this, "productCountryOfOriginFieldSave"]); |
| 95 |
|
| 96 |
// Add barcode in order grid |
| 97 |
add_filter("manage_edit-shop_order_columns", [$this, "barcode_add_new_order_admin_list_column"], 10, 1); |
| 98 |
add_action("manage_shop_order_posts_custom_column", [$this, "addBarcodeToOrderColumn"], 10, 2); |
| 99 |
|
| 100 |
add_action('woocommerce_payment_complete', [$this, 'automaticExportOrder'], 1000); |
| 101 |
|
| 102 |
add_action("init", [$this, "registerDeliveredPostStatus"], 10, 1); |
| 103 |
add_filter("wc_order_statuses", [$this, "displayDeliveredPostStatus"], 10, 2); |
| 104 |
|
| 105 |
add_action('woocommerce_product_after_variable_attributes', array($this, 'variation_hs_code_field'), 10, 3); |
| 106 |
add_action('woocommerce_save_product_variation', array($this, 'save_variation_hs_code_field'), 10, 2); |
| 107 |
add_filter('woocommerce_available_variation', array($this, 'load_variation_hs_code_field'), 10, 1); |
| 108 |
} |
| 109 |
|
| 110 |
/** |
| 111 |
* @param \MyParcelNL\Sdk\src\Adapter\DeliveryOptions\AbstractDeliveryOptionsAdapter $deliveryOptions |
| 112 |
*/ |
| 113 |
public static function renderPickupLocation(DeliveryOptions $deliveryOptions): void |
| 114 |
{ |
| 115 |
if (! $deliveryOptions->isPickup()) { |
| 116 |
return; |
| 117 |
} |
| 118 |
|
| 119 |
$pickup = $deliveryOptions->getPickupLocation(); |
| 120 |
|
| 121 |
printf( |
| 122 |
"<div class=\"pickup-location\"><strong>%s:</strong><br /> %s<br />%s %s<br />%s %s</div>", |
| 123 |
__("Pickup location", "woocommerce-postnl"), |
| 124 |
$pickup->getLocationName(), |
| 125 |
$pickup->getStreet(), |
| 126 |
$pickup->getNumber(), |
| 127 |
$pickup->getPostalCode(), |
| 128 |
$pickup->getCity() |
| 129 |
); |
| 130 |
|
| 131 |
echo "<hr>"; |
| 132 |
} |
| 133 |
|
| 134 |
/** |
| 135 |
* @param $loop |
| 136 |
* @param $variationData |
| 137 |
* @param $variation |
| 138 |
*/ |
| 139 |
public function variation_hs_code_field($loop, $variationData, $variation) |
| 140 |
{ |
| 141 |
woocommerce_wp_text_input( |
| 142 |
array( |
| 143 |
'id' => self::META_HS_CODE_VARIATION . "[{$loop}]", |
| 144 |
'name' => self::META_HS_CODE_VARIATION . "[{$loop}]", |
| 145 |
'value' => get_post_meta($variation->ID, self::META_HS_CODE_VARIATION, true), |
| 146 |
'label' => __('HS Code', 'woocommerce'), |
| 147 |
'desc_tip' => true, |
| 148 |
'description' => __('This HS Code overwrites the parents HS Code.', 'woocommerce'), |
| 149 |
'wrapper_class' => 'form-row form-row-full', |
| 150 |
) |
| 151 |
); |
| 152 |
} |
| 153 |
|
| 154 |
/** |
| 155 |
* @param $variationId |
| 156 |
* @param $loop |
| 157 |
*/ |
| 158 |
public function save_variation_hs_code_field($variationId, $loop) |
| 159 |
{ |
| 160 |
$hsCodeValue = $_POST[self::META_HS_CODE_VARIATION][$loop]; |
| 161 |
|
| 162 |
if (! empty($hsCodeValue)) { |
| 163 |
update_post_meta($variationId, self::META_HS_CODE_VARIATION, esc_attr($hsCodeValue)); |
| 164 |
} |
| 165 |
} |
| 166 |
|
| 167 |
/** |
| 168 |
* @param $variation |
| 169 |
* |
| 170 |
* @return mixed |
| 171 |
*/ |
| 172 |
public function load_variation_hs_code_field($variation) |
| 173 |
{ |
| 174 |
$variation[self::META_HS_CODE_VARIATION] = get_post_meta($variation['variation_id'], self::META_HS_CODE_VARIATION, true); |
| 175 |
|
| 176 |
return $variation; |
| 177 |
} |
| 178 |
|
| 179 |
/** |
| 180 |
* Add delivered post type to order statuses list |
| 181 |
*/ |
| 182 |
public function registerDeliveredPostStatus(): void |
| 183 |
{ |
| 184 |
register_post_status('wc-custom-delivered', |
| 185 |
[ |
| 186 |
'label' => 'Delivered', |
| 187 |
'public' => true, |
| 188 |
'exclude_from_search' => false, |
| 189 |
'show_in_admin_all_list' => true, |
| 190 |
'show_in_admin_status_list' => true, |
| 191 |
'label_count' => _n_noop('Delivered (%s)', 'Delivered (%s)'), |
| 192 |
] |
| 193 |
); |
| 194 |
} |
| 195 |
|
| 196 |
/** |
| 197 |
* @param array $order_statuses |
| 198 |
* |
| 199 |
* @return array |
| 200 |
*/ |
| 201 |
public function displayDeliveredPostStatus(array $order_statuses): array |
| 202 |
{ |
| 203 |
$new_order_statuses = []; |
| 204 |
|
| 205 |
foreach ($order_statuses as $key => $status) { |
| 206 |
$new_order_statuses[$key] = $status; |
| 207 |
|
| 208 |
if ('wc-processing' === $key) { |
| 209 |
$new_order_statuses['wc-custom-delivered'] = 'Delivered'; |
| 210 |
} |
| 211 |
} |
| 212 |
|
| 213 |
return $new_order_statuses; |
| 214 |
} |
| 215 |
|
| 216 |
/** |
| 217 |
* @param $orderId |
| 218 |
* |
| 219 |
* @throws ErrorException |
| 220 |
* @throws \MyParcelNL\Sdk\src\Exception\ApiException |
| 221 |
* @throws \use MyParcelNL\Sdk\src\Exception\MissingFieldException |
| 222 |
*/ |
| 223 |
public function automaticExportOrder($orderId): void |
| 224 |
{ |
| 225 |
(new WCPN_Export())->exportByOrderId($orderId); |
| 226 |
} |
| 227 |
|
| 228 |
/** |
| 229 |
* @param WC_Order $order |
| 230 |
* |
| 231 |
* @throws Exception |
| 232 |
*/ |
| 233 |
public function showPostNLSettings(WC_Order $order): void |
| 234 |
{ |
| 235 |
$isAllowedDestination = WCPN_Country_Codes::isAllowedDestination(WCX_Order::get_prop($order, 'shipping_country')); |
| 236 |
|
| 237 |
if (! $isAllowedDestination) { |
| 238 |
return; |
| 239 |
} |
| 240 |
|
| 241 |
$order_id = WCX_Order::get_id($order); |
| 242 |
$consignments = WCPOST_Admin::get_order_shipments($order); |
| 243 |
$deliveryOptions = self::getDeliveryOptionsFromOrder($order); |
| 244 |
$packageType = $deliveryOptions->getPackageType() ?? WCPOST()->export->getPackageTypeFromOrder($order); |
| 245 |
|
| 246 |
echo '<div class="wcpn__shipment-settings-wrapper" style="display: none;">'; |
| 247 |
|
| 248 |
$this->printDeliveryDate($deliveryOptions); |
| 249 |
|
| 250 |
// if we have shipments, then we show status & link to Track & Trace, settings under i |
| 251 |
if (! empty($consignments)) : |
| 252 |
// only use last shipment |
| 253 |
$lastShipment = array_pop($consignments); |
| 254 |
$lastShipmentId = $lastShipment['shipment_id']; |
| 255 |
|
| 256 |
?> |
| 257 |
<a class="wcpn__shipment-summary__show"> |
| 258 |
<span class="wcpn__encircle wcpn__shipment-summary__show">i</span> |
| 259 |
</a> |
| 260 |
<div |
| 261 |
class="wcpn__box wcpn__shipment-summary__list" |
| 262 |
data-loaded="" |
| 263 |
data-shipment_id="<?php echo $lastShipmentId; ?>" |
| 264 |
data-order_id="<?php echo $order_id; ?>" |
| 265 |
style="display: none;"> |
| 266 |
<?php self::renderSpinner(); ?> |
| 267 |
</div> |
| 268 |
<?php endif; |
| 269 |
|
| 270 |
printf( |
| 271 |
'<a href="#" class="wcpn__shipment-options__show" data-order-id="%d">%s ▾</a>', |
| 272 |
$order->get_id(), |
| 273 |
WCPN_Export::getPackageTypeHuman($packageType) |
| 274 |
); |
| 275 |
|
| 276 |
echo "</div>"; |
| 277 |
} |
| 278 |
|
| 279 |
/** |
| 280 |
* Get shipment status + Track & Trace link via AJAX |
| 281 |
* |
| 282 |
* @throws Exception |
| 283 |
*/ |
| 284 |
public function order_list_ajax_get_shipment_summary() |
| 285 |
{ |
| 286 |
check_ajax_referer(WCPOST::NONCE_ACTION, 'security'); |
| 287 |
|
| 288 |
include('views/html-order-shipment-summary.php'); |
| 289 |
die(); |
| 290 |
} |
| 291 |
|
| 292 |
/** |
| 293 |
* Add export option to bulk action drop down menu. |
| 294 |
* |
| 295 |
* @param array $actions |
| 296 |
* |
| 297 |
* @return array |
| 298 |
* @since WordPress 4.7.0 |
| 299 |
*/ |
| 300 |
public function addBulkActions(array $actions): array |
| 301 |
{ |
| 302 |
$actions = array_merge( |
| 303 |
$actions, |
| 304 |
[ |
| 305 |
self::BULK_ACTION_EXPORT => __("PostNL: Prepare shipment", "woocommerce-postnl"), |
| 306 |
self::BULK_ACTION_PRINT => __("PostNL: Print", "woocommerce-postnl"), |
| 307 |
self::BULK_ACTION_EXPORT_PRINT => __("PostNL: Prepare & print shipment", "woocommerce-postnl"), |
| 308 |
] |
| 309 |
); |
| 310 |
|
| 311 |
self::renderSpinner('bulkAction'); |
| 312 |
|
| 313 |
return $actions; |
| 314 |
} |
| 315 |
|
| 316 |
/** |
| 317 |
* Add export option to bulk action drop down menu |
| 318 |
* Using Javascript until WordPress core fixes: http://core.trac.wordpress.org/ticket/16031 |
| 319 |
* |
| 320 |
* Used pre WordPress 4.7.0 |
| 321 |
* |
| 322 |
* @access public |
| 323 |
* @return void |
| 324 |
*/ |
| 325 |
public function bulk_actions() |
| 326 |
{ |
| 327 |
global $post_type; |
| 328 |
$bulk_actions = [ |
| 329 |
self::BULK_ACTION_EXPORT => __("PostNL: Prepare shipment", "woocommerce-postnl"), |
| 330 |
self::BULK_ACTION_PRINT => __("PostNL: Print", "woocommerce-postnl"), |
| 331 |
self::BULK_ACTION_EXPORT_PRINT => __("PostNL: Prepare & print shipment", "woocommerce-postnl"), |
| 332 |
]; |
| 333 |
|
| 334 |
if ('shop_order' == $post_type) { |
| 335 |
?> |
| 336 |
<script type="text/javascript"> |
| 337 |
jQuery(document).ready(function () { |
| 338 |
<?php foreach ($bulk_actions as $action => $title) { ?> |
| 339 |
jQuery('<option>') |
| 340 |
.val('<?php echo $action; ?>') |
| 341 |
.html('<?php echo esc_attr($title); ?>') |
| 342 |
.appendTo('select[name=\'action\'], select[name=\'action2\']'); |
| 343 |
<?php } ?> |
| 344 |
}); |
| 345 |
</script> |
| 346 |
<?php |
| 347 |
self::renderSpinner(); |
| 348 |
} |
| 349 |
} |
| 350 |
|
| 351 |
/** |
| 352 |
* Show dialog to choose print position (offset) |
| 353 |
* |
| 354 |
* @access public |
| 355 |
* @return void |
| 356 |
*/ |
| 357 |
public function renderOffsetDialog(): void |
| 358 |
{ |
| 359 |
if (! WCPOST()->setting_collection->isEnabled(WCPOST_Settings::SETTING_ASK_FOR_PRINT_POSITION)) { |
| 360 |
return; |
| 361 |
} |
| 362 |
|
| 363 |
$field = [ |
| 364 |
"name" => "offset", |
| 365 |
"class" => ["wcpn__d--inline-block"], |
| 366 |
"input_class" => ["wcpn__offset-dialog__offset"], |
| 367 |
"type" => "number", |
| 368 |
"label" => __("Labels to skip", "woocommerce-postnl"), |
| 369 |
"custom_attributes" => [ |
| 370 |
"step" => "1", |
| 371 |
"min" => "0", |
| 372 |
"max" => "4", |
| 373 |
"size" => "2", |
| 374 |
], |
| 375 |
]; |
| 376 |
|
| 377 |
$class = new SettingsFieldArguments($field); |
| 378 |
?> |
| 379 |
|
| 380 |
<div |
| 381 |
class="wcpn wcpn__box wcpn__offset-dialog" |
| 382 |
style="display: none;"> |
| 383 |
<div class="wcpn__offset-dialog__inner wcpn__d--flex"> |
| 384 |
<div> |
| 385 |
<?php woocommerce_form_field($field["name"], $class->getArguments(false), ""); ?> |
| 386 |
|
| 387 |
<img |
| 388 |
src="<?php echo WCPOST()->plugin_url() . "/assets/img/print-offset-icon.png"; ?>" |
| 389 |
alt="<?php implode(", ", WCPN_Export::DEFAULT_POSITIONS) ?>" |
| 390 |
class="wcpn__offset-dialog__icon"/> |
| 391 |
<div> |
| 392 |
<a |
| 393 |
href="#" |
| 394 |
class="wcpn__action wcpn__offset-dialog__button button"> |
| 395 |
<?php _e("Print", "woocommerce-postnl"); ?> |
| 396 |
<?php WCPOST_Admin::renderSpinner(); ?> |
| 397 |
</a> |
| 398 |
</div> |
| 399 |
</div> |
| 400 |
<div class="wcpn__close-button dashicons dashicons-no-alt wcpn__offset-dialog__close"></div> |
| 401 |
</div> |
| 402 |
</div> |
| 403 |
<?php |
| 404 |
} |
| 405 |
|
| 406 |
/** |
| 407 |
* Hide an empty shipment options form in the footer. |
| 408 |
*/ |
| 409 |
public function renderShipmentOptionsForm(): void |
| 410 |
{ |
| 411 |
echo '<div class="wcpn__box wcpn__shipment-options-dialog" style="display: none; position: absolute;"></div>'; |
| 412 |
} |
| 413 |
|
| 414 |
/** |
| 415 |
* Get the new html content for the shipment options form based on the passed order id. |
| 416 |
*/ |
| 417 |
public function ajaxGetShipmentOptions(): void |
| 418 |
{ |
| 419 |
// Order is used in views/html-order-shipment-options.php |
| 420 |
$order = wc_get_order((int) $_POST['orderId']); |
| 421 |
|
| 422 |
include('views/html-order-shipment-options.php'); |
| 423 |
|
| 424 |
die(); |
| 425 |
} |
| 426 |
|
| 427 |
/** |
| 428 |
* Add print actions to the orders listing |
| 429 |
* |
| 430 |
* @param $order |
| 431 |
* |
| 432 |
* @throws Exception |
| 433 |
*/ |
| 434 |
public function showOrderActions($order): void |
| 435 |
{ |
| 436 |
if (empty($order)) { |
| 437 |
return; |
| 438 |
} |
| 439 |
|
| 440 |
$shipping_country = WCX_Order::get_prop($order, 'shipping_country'); |
| 441 |
|
| 442 |
if (! WCPN_Country_Codes::isAllowedDestination($shipping_country)) { |
| 443 |
return; |
| 444 |
} |
| 445 |
|
| 446 |
$order_id = WCX_Order::get_id($order); |
| 447 |
|
| 448 |
$baseUrl = "admin-ajax.php?action=" . WCPN_Export::EXPORT; |
| 449 |
$addShipments = WCPN_Export::ADD_SHIPMENTS; |
| 450 |
$getLabels = WCPN_Export::GET_LABELS; |
| 451 |
|
| 452 |
$listing_actions = [ |
| 453 |
$addShipments => [ |
| 454 |
"url" => admin_url("$baseUrl&request=$addShipments&order_ids=$order_id"), |
| 455 |
"img" => WCPOST()->plugin_url() . "/assets/img/postnl-up.png", |
| 456 |
"alt" => __("Export to PostNL", "woocommerce-postnl"), |
| 457 |
], |
| 458 |
$getLabels => [ |
| 459 |
"url" => admin_url("$baseUrl&request=$getLabels&order_ids=$order_id"), |
| 460 |
"img" => WCPOST()->plugin_url() . "/assets/img/postnl-pdf.png", |
| 461 |
"alt" => __("Print PostNL label", "woocommerce-postnl"), |
| 462 |
], |
| 463 |
]; |
| 464 |
|
| 465 |
$consignments = WCPOST_Admin::get_order_shipments($order); |
| 466 |
|
| 467 |
if (empty($consignments)) { |
| 468 |
unset($listing_actions[$getLabels]); |
| 469 |
} |
| 470 |
|
| 471 |
$display = WCPOST()->setting_collection->getByName(WCPOST_Settings::SETTING_DOWNLOAD_DISPLAY) === 'display'; |
| 472 |
|
| 473 |
$attributes = []; |
| 474 |
|
| 475 |
if ($display) { |
| 476 |
$attributes["target"] = "_blank"; |
| 477 |
} |
| 478 |
|
| 479 |
foreach ($listing_actions as $request => $data) { |
| 480 |
self::renderAction( |
| 481 |
$data['url'], |
| 482 |
$data['alt'], |
| 483 |
$data["img"], |
| 484 |
$attributes |
| 485 |
); |
| 486 |
} |
| 487 |
} |
| 488 |
|
| 489 |
/** |
| 490 |
* @param WC_Order $order |
| 491 |
* @param bool $exclude_concepts |
| 492 |
* |
| 493 |
* @return array |
| 494 |
*/ |
| 495 |
public static function get_order_shipments(WC_Order $order, bool $exclude_concepts = false): array |
| 496 |
{ |
| 497 |
$consignments = WCX_Order::get_meta($order, self::META_SHIPMENTS); |
| 498 |
|
| 499 |
// fallback to legacy consignment data (v1.X) |
| 500 |
if (empty($consignments)) { |
| 501 |
if ($consignment_id = WCX_Order::get_meta($order, self::META_CONSIGNMENT_ID)) { |
| 502 |
$consignments = [ |
| 503 |
[ |
| 504 |
"shipment_id" => $consignment_id, |
| 505 |
"track_trace" => WCX_Order::get_meta($order, self::META_TRACK_TRACE), |
| 506 |
], |
| 507 |
]; |
| 508 |
} elseif ($legacy_consignments = WCX_Order::get_meta($order, self::META_CONSIGNMENTS)) { |
| 509 |
$consignments = []; |
| 510 |
foreach ($legacy_consignments as $consignment) { |
| 511 |
if (isset($consignment["consignment_id"])) { |
| 512 |
$consignments[] = [ |
| 513 |
"shipment_id" => $consignment["consignment_id"], |
| 514 |
"track_trace" => $consignment["track_trace"], |
| 515 |
]; |
| 516 |
} |
| 517 |
} |
| 518 |
} |
| 519 |
} |
| 520 |
|
| 521 |
if (empty($consignments) || ! is_array($consignments)) { |
| 522 |
return []; |
| 523 |
} |
| 524 |
|
| 525 |
/** |
| 526 |
* Filter out concepts. |
| 527 |
*/ |
| 528 |
if ($exclude_concepts) { |
| 529 |
$consignments = array_filter($consignments, |
| 530 |
function($consignment) { |
| 531 |
return isset($consignment["track_trace"]); |
| 532 |
} |
| 533 |
); |
| 534 |
} |
| 535 |
|
| 536 |
return $consignments; |
| 537 |
} |
| 538 |
|
| 539 |
/** |
| 540 |
* On saving shipment options from the bulk options form. |
| 541 |
* |
| 542 |
* @throws Exception |
| 543 |
* @see admin/views/html-order-shipment-options.php |
| 544 |
*/ |
| 545 |
public function save_shipment_options_ajax(): void |
| 546 |
{ |
| 547 |
parse_str($_POST["form_data"], $form_data); |
| 548 |
|
| 549 |
foreach ($form_data[self::SHIPMENT_OPTIONS_FORM_NAME] as $order_id => $data) { |
| 550 |
$order = WCX::get_order($order_id); |
| 551 |
$shippingCountry = $order->get_shipping_country(); |
| 552 |
$data = self::removeDisallowedDeliveryOptions($data, $shippingCountry); |
| 553 |
$deliveryOptions = self::getDeliveryOptionsFromOrder($order, $data); |
| 554 |
|
| 555 |
error_log( |
| 556 |
sprintf( |
| 557 |
"Saving delivery options for order %d\n%s", |
| 558 |
$order_id, |
| 559 |
json_encode( |
| 560 |
$deliveryOptions->toArray(), |
| 561 |
JSON_PRETTY_PRINT |
| 562 |
) |
| 563 |
) |
| 564 |
); |
| 565 |
|
| 566 |
WCX_Order::update_meta_data( |
| 567 |
$order, |
| 568 |
self::META_DELIVERY_OPTIONS, |
| 569 |
$deliveryOptions |
| 570 |
); |
| 571 |
|
| 572 |
// Save extra options |
| 573 |
WCX_Order::update_meta_data( |
| 574 |
$order, |
| 575 |
self::META_SHIPMENT_OPTIONS_EXTRA, |
| 576 |
$data["extra_options"] |
| 577 |
); |
| 578 |
} |
| 579 |
|
| 580 |
die(); |
| 581 |
} |
| 582 |
|
| 583 |
/** |
| 584 |
* Add the meta box on the single order page |
| 585 |
*/ |
| 586 |
public function add_order_meta_box(): void |
| 587 |
{ |
| 588 |
add_meta_box( |
| 589 |
"postnl", |
| 590 |
__("PostNL", "woocommerce-postnl"), |
| 591 |
[$this, "createMetaBox"], |
| 592 |
"shop_order", |
| 593 |
"side", |
| 594 |
"default" |
| 595 |
); |
| 596 |
} |
| 597 |
|
| 598 |
/** |
| 599 |
* Callback: Create the meta box content on the single order page |
| 600 |
* |
| 601 |
* @throws Exception |
| 602 |
*/ |
| 603 |
public function createMetaBox(): void |
| 604 |
{ |
| 605 |
global $post_id; |
| 606 |
// get order |
| 607 |
$order = WCX::get_order($post_id); |
| 608 |
|
| 609 |
if (! $order) { |
| 610 |
return; |
| 611 |
} |
| 612 |
|
| 613 |
$order_id = WCX_Order::get_id($order); |
| 614 |
|
| 615 |
$shipping_country = WCX_Order::get_prop($order, 'shipping_country'); |
| 616 |
if (! WCPN_Country_Codes::isAllowedDestination($shipping_country)) { |
| 617 |
return; |
| 618 |
} |
| 619 |
|
| 620 |
$class = version_compare(WOOCOMMERCE_VERSION, '3.3.0', '>=') ? "single_wc_actions" : "single_order_actions"; |
| 621 |
// show buttons and check if WooCommerce > 3.3.0 is used and select the correct function and class |
| 622 |
echo "<div class=\"$class\">"; |
| 623 |
$this->showOrderActions($order); |
| 624 |
echo '</div>'; |
| 625 |
|
| 626 |
$downloadDisplay = WCPOST()->setting_collection->getByName(WCPOST_Settings::SETTING_DOWNLOAD_DISPLAY) === 'display'; |
| 627 |
$consignments = WCPOST_Admin::get_order_shipments($order); |
| 628 |
|
| 629 |
// show shipments if available |
| 630 |
if (empty($consignments)) { |
| 631 |
return; |
| 632 |
} |
| 633 |
|
| 634 |
include('views/html-order-track-trace-table.php'); |
| 635 |
} |
| 636 |
|
| 637 |
/** |
| 638 |
* @param $order |
| 639 |
* |
| 640 |
* @throws Exception |
| 641 |
*/ |
| 642 |
public function single_order_shipment_options(WC_Order $order) |
| 643 |
{ |
| 644 |
$shipping_country = WCX_Order::get_prop($order, "shipping_country"); |
| 645 |
|
| 646 |
if (! WCPN_Country_Codes::isAllowedDestination($shipping_country)) { |
| 647 |
return; |
| 648 |
} |
| 649 |
|
| 650 |
$this->showPostNLSettings($order); |
| 651 |
} |
| 652 |
|
| 653 |
/** |
| 654 |
* @param \WC_Order $order |
| 655 |
* |
| 656 |
* @throws \Exception |
| 657 |
*/ |
| 658 |
public function showDeliveryDateForOrder(WC_Order $order): void |
| 659 |
{ |
| 660 |
$deliveryOptions = self::getDeliveryOptionsFromOrder($order); |
| 661 |
$this->printDeliveryDate($deliveryOptions); |
| 662 |
} |
| 663 |
|
| 664 |
/** |
| 665 |
* @param $order_id |
| 666 |
* @param $track_trace |
| 667 |
* |
| 668 |
* @return string|void |
| 669 |
* @throws Exception |
| 670 |
*/ |
| 671 |
public static function getTrackTraceUrl($order_id, $track_trace) |
| 672 |
{ |
| 673 |
if (empty($order_id)) { |
| 674 |
return; |
| 675 |
} |
| 676 |
|
| 677 |
$order = WCX::get_order($order_id); |
| 678 |
$country = WCX_Order::get_prop($order, 'shipping_country'); |
| 679 |
$postcode = preg_replace('/\s+/', '', WCX_Order::get_prop($order, 'shipping_postcode')); |
| 680 |
|
| 681 |
// set url for NL or foreign orders |
| 682 |
if ($country === 'NL') { |
| 683 |
$deliveryOptions = self::getDeliveryOptionsFromOrder($order); |
| 684 |
|
| 685 |
// use billing postcode for pickup/pakjegemak |
| 686 |
if ($deliveryOptions->isPickup()) { |
| 687 |
$postcode = preg_replace('/\s+/', '', WCX_Order::get_prop($order, 'billing_postcode')); |
| 688 |
} |
| 689 |
|
| 690 |
$trackTraceUrl = sprintf( |
| 691 |
'https://jouw.postnl.nl/track-and-trace/%s/%s/%s', |
| 692 |
$track_trace, |
| 693 |
$country, |
| 694 |
$postcode |
| 695 |
); |
| 696 |
} else { |
| 697 |
$trackTraceUrl = sprintf( |
| 698 |
'https://www.internationalparceltracking.com/Main.aspx#/track/%s/%s/%s', |
| 699 |
$track_trace, |
| 700 |
$country, |
| 701 |
$postcode |
| 702 |
); |
| 703 |
} |
| 704 |
|
| 705 |
return $trackTraceUrl; |
| 706 |
} |
| 707 |
|
| 708 |
public function productHsCodeField() |
| 709 |
{ |
| 710 |
echo '<div class="options_group">'; |
| 711 |
woocommerce_wp_text_input( |
| 712 |
[ |
| 713 |
'id' => self::META_HS_CODE, |
| 714 |
'label' => __('HS Code', 'woocommerce-postnl'), |
| 715 |
'description' => sprintf( |
| 716 |
__('HS Codes are used for PostNL world shipments, you can find the appropriate code on the %ssite of the Dutch Customs%s.', |
| 717 |
'woocommerce-postnl' |
| 718 |
), |
| 719 |
'<a href="http://tarief.douane.nl/arctictariff-public-web/#!/home" target="_blank">', |
| 720 |
'</a>' |
| 721 |
), |
| 722 |
] |
| 723 |
); |
| 724 |
echo '</div>'; |
| 725 |
} |
| 726 |
|
| 727 |
public function productHsCodeFieldSave($post_id) |
| 728 |
{ |
| 729 |
// check if hs code is passed and not an array (=variation hs code) |
| 730 |
if (isset($_POST[self::META_HS_CODE]) && ! is_array($_POST[self::META_HS_CODE])) { |
| 731 |
$product = wc_get_product($post_id); |
| 732 |
$hs_code = $_POST[self::META_HS_CODE]; |
| 733 |
if (! empty($hs_code)) { |
| 734 |
WCX_Product::update_meta_data($product, self::META_HS_CODE, esc_attr($hs_code)); |
| 735 |
} else { |
| 736 |
if (isset($_POST[self::META_HS_CODE]) && empty($hs_code)) { |
| 737 |
WCX_Product::delete_meta_data($product, self::META_HS_CODE); |
| 738 |
} |
| 739 |
} |
| 740 |
} |
| 741 |
} |
| 742 |
|
| 743 |
public function productCountryOfOriginField() |
| 744 |
{ |
| 745 |
echo '<div class="options_group">'; |
| 746 |
woocommerce_wp_text_input( |
| 747 |
[ |
| 748 |
'id' => self::META_COUNTRY_OF_ORIGIN, |
| 749 |
'label' => __('Country of Origin', 'woocommerce-postnl'), |
| 750 |
'type' => 'select', |
| 751 |
'options' => (new WC_Countries())->get_countries(), |
| 752 |
'description' => sprintf( |
| 753 |
__('Country of origin is required for world shipments. Defaults to shop base.') |
| 754 |
), |
| 755 |
] |
| 756 |
); |
| 757 |
echo '</div>'; |
| 758 |
} |
| 759 |
|
| 760 |
public function productCountryOfOriginFieldSave($postId) |
| 761 |
{ |
| 762 |
if (isset($_POST[self::META_COUNTRY_OF_ORIGIN]) && ! is_array($_POST[self::META_COUNTRY_OF_ORIGIN])) { |
| 763 |
$product = wc_get_product($postId); |
| 764 |
$countryOfOrigin = $_POST[self::META_COUNTRY_OF_ORIGIN]; |
| 765 |
if (! empty($countryOfOrigin)) { |
| 766 |
WCX_Product::update_meta_data($product, self::META_COUNTRY_OF_ORIGIN, esc_attr($countryOfOrigin)); |
| 767 |
|
| 768 |
return; |
| 769 |
} |
| 770 |
if (isset($_POST[self::META_COUNTRY_OF_ORIGIN]) && empty($countryOfOrigin)) { |
| 771 |
WCX_Product::delete_meta_data($product, self::META_COUNTRY_OF_ORIGIN); |
| 772 |
} |
| 773 |
} |
| 774 |
|
| 775 |
return; |
| 776 |
} |
| 777 |
|
| 778 |
/** |
| 779 |
* @snippet Add Column to Orders Table (e.g. Barcode) - WooCommerce |
| 780 |
* |
| 781 |
* @param $columns |
| 782 |
* |
| 783 |
* @return mixed |
| 784 |
*/ |
| 785 |
public function barcode_add_new_order_admin_list_column($columns) |
| 786 |
{ |
| 787 |
// I want to display Barcode column just after the date column |
| 788 |
return array_slice($columns, 0, 6, true) + ['barcode' => 'Barcode'] + array_slice($columns, 6, null, true); |
| 789 |
} |
| 790 |
|
| 791 |
/** |
| 792 |
* @param $column |
| 793 |
* |
| 794 |
* @throws Exception |
| 795 |
*/ |
| 796 |
public function addBarcodeToOrderColumn($column) |
| 797 |
{ |
| 798 |
global $post; |
| 799 |
|
| 800 |
if ("barcode" === $column) { |
| 801 |
$this->renderBarcodes(WCX::get_order($post->ID)); |
| 802 |
} |
| 803 |
} |
| 804 |
|
| 805 |
/** |
| 806 |
* @param WC_Order $order |
| 807 |
* |
| 808 |
* @return void |
| 809 |
* @throws Exception |
| 810 |
*/ |
| 811 |
public function renderBarcodes(WC_Order $order): void |
| 812 |
{ |
| 813 |
$shipments = WCPOST_Admin::get_order_shipments($order, true); |
| 814 |
|
| 815 |
if (empty($shipments)) { |
| 816 |
echo __("No label has been created yet.", "woocommerce-postnl"); |
| 817 |
|
| 818 |
return; |
| 819 |
} |
| 820 |
|
| 821 |
echo '<div class="wcpn__barcodes">'; |
| 822 |
foreach ($shipments as $shipment_id => $shipment) { |
| 823 |
if (empty($shipment["track_trace"])) { |
| 824 |
echo __("Concept created but not printed.", "woocommerce-postnl"); |
| 825 |
} else { |
| 826 |
printf( |
| 827 |
'<a target="_blank" class="wcpn__barcode-link" title="%2$s" href="%1$s">%2$s</a><br>', |
| 828 |
WCPOST_Admin::getTrackTraceUrl($order, $shipment["track_trace"]), |
| 829 |
$shipment["track_trace"] |
| 830 |
); |
| 831 |
} |
| 832 |
} |
| 833 |
echo "</div>"; |
| 834 |
} |
| 835 |
|
| 836 |
/** |
| 837 |
* Get DeliveryOptions object from the given order's meta data. Uses legacy delivery options if found, if that |
| 838 |
* data is invalid it falls back to defaults. |
| 839 |
* |
| 840 |
* @param WC_Order $order |
| 841 |
* @param array $inputData |
| 842 |
* |
| 843 |
* @return DeliveryOptions |
| 844 |
* @throws \Exception |
| 845 |
* @see \WCPN_Checkout::save_delivery_options |
| 846 |
*/ |
| 847 |
public static function getDeliveryOptionsFromOrder(WC_Order $order, array $inputData = []): DeliveryOptions |
| 848 |
{ |
| 849 |
$meta = WCX_Order::get_meta($order, self::META_DELIVERY_OPTIONS) ?: null; |
| 850 |
|
| 851 |
// $meta is a json string, create an instance |
| 852 |
if (! empty($meta) && ! $meta instanceof DeliveryOptions) { |
| 853 |
if (is_string($meta)) { |
| 854 |
$meta = json_decode(stripslashes($meta), true); |
| 855 |
} |
| 856 |
|
| 857 |
$meta["carrier"] = WCPN_Data::DEFAULT_CARRIER; |
| 858 |
|
| 859 |
try { |
| 860 |
// create new instance from known json |
| 861 |
$meta = DeliveryOptionsAdapterFactory::create((array) $meta); |
| 862 |
} catch (BadMethodCallException $e) { |
| 863 |
// create new instance from unknown json data |
| 864 |
$meta = new WCPN_DeliveryOptionsFromOrderAdapter(null, (array) $meta); |
| 865 |
} |
| 866 |
} |
| 867 |
|
| 868 |
// Create or update immutable adapter from order with a instanceof DeliveryOptionsAdapter |
| 869 |
if (empty($meta) || ! empty($inputData)) { |
| 870 |
$meta = new WCPN_DeliveryOptionsFromOrderAdapter($meta, $inputData); |
| 871 |
} |
| 872 |
|
| 873 |
return $meta; |
| 874 |
} |
| 875 |
|
| 876 |
/** |
| 877 |
* Output the delivery date if there is a date and the show delivery day setting is enabled. |
| 878 |
* |
| 879 |
* @param DeliveryOptions $deliveryOptions |
| 880 |
* |
| 881 |
* @throws Exception |
| 882 |
*/ |
| 883 |
private function printDeliveryDate(DeliveryOptions $deliveryOptions): void |
| 884 |
{ |
| 885 |
$showDeliveryDay = WCPOST()->setting_collection->isEnabled(WCPOST_Settings::SETTING_SHOW_DELIVERY_DAY); |
| 886 |
|
| 887 |
if ($deliveryOptions->getDate() && $showDeliveryDay) { |
| 888 |
printf( |
| 889 |
'<div class="delivery-date"><strong>%s</strong><br />%s, %s</div>', |
| 890 |
__("PostNL shipment:", "woocommerce-postnl"), |
| 891 |
WCPN_Data::getDeliveryTypesHuman()[$deliveryOptions->getDeliveryType()], |
| 892 |
wc_format_datetime(new WC_DateTime($deliveryOptions->getDate()), 'D d-m') |
| 893 |
); |
| 894 |
} |
| 895 |
} |
| 896 |
|
| 897 |
/** |
| 898 |
* Output a spinner. |
| 899 |
* |
| 900 |
* @param string $state |
| 901 |
* @param array $args |
| 902 |
*/ |
| 903 |
public static function renderSpinner(string $state = "", array $args = []): void |
| 904 |
{ |
| 905 |
$spinners = [ |
| 906 |
"loading" => get_site_url() . "/wp-admin/images/spinner.gif", |
| 907 |
"success" => get_site_url() . "/wp-admin/images/yes.png", |
| 908 |
"failed" => get_site_url() . "/wp-admin/images/no.png", |
| 909 |
]; |
| 910 |
|
| 911 |
$arguments = []; |
| 912 |
|
| 913 |
$args["class"][] = "wcpn__spinner"; |
| 914 |
|
| 915 |
if ($state) { |
| 916 |
$args["class"][] = "wcpn__spinner--$state"; |
| 917 |
} |
| 918 |
|
| 919 |
foreach ($args as $arg => $value) { |
| 920 |
if (is_array($value)) { |
| 921 |
$value = implode(" ", $value); |
| 922 |
} |
| 923 |
$arguments[] = "$arg=\"$value\""; |
| 924 |
} |
| 925 |
|
| 926 |
$attributes = implode(" ", $arguments); |
| 927 |
|
| 928 |
echo "<span $attributes>"; |
| 929 |
foreach ($spinners as $spinnerState => $icon) { |
| 930 |
printf( |
| 931 |
'<img class="wcpn__spinner__%1$s" alt="%1$s" src="%2$s" style="display: %3$s;" />', |
| 932 |
$spinnerState, |
| 933 |
$icon, |
| 934 |
$state === $spinnerState ? "block" : "none" |
| 935 |
); |
| 936 |
} |
| 937 |
echo '</span>'; |
| 938 |
} |
| 939 |
|
| 940 |
/** |
| 941 |
* @param string $url |
| 942 |
* @param string $alt |
| 943 |
* @param string $icon |
| 944 |
* @param array $rawAttributes |
| 945 |
*/ |
| 946 |
public static function renderAction(string $url, string $alt, string $icon, array $rawAttributes = []): void |
| 947 |
{ |
| 948 |
printf( |
| 949 |
'<a href="%1$s" |
| 950 |
class="button tips wcpn__action wcpn__d--flex" |
| 951 |
data-tip="%2$s" |
| 952 |
%4$s> |
| 953 |
<img class="wcpn__action__img" src="%3$s" alt="%2$s" />', |
| 954 |
wp_nonce_url($url, WCPOST::NONCE_ACTION), |
| 955 |
$alt, |
| 956 |
$icon, |
| 957 |
wc_implode_html_attributes($rawAttributes) |
| 958 |
); |
| 959 |
|
| 960 |
self::renderSpinner(); |
| 961 |
echo "</a>"; |
| 962 |
} |
| 963 |
|
| 964 |
/** |
| 965 |
* @param array $shipment |
| 966 |
* @param int $order_id |
| 967 |
* |
| 968 |
* @throws Exception |
| 969 |
*/ |
| 970 |
public static function renderTrackTraceLink(array $shipment, int $order_id): void |
| 971 |
{ |
| 972 |
$track_trace = $shipment["track_trace"] ?? null; |
| 973 |
|
| 974 |
if ($track_trace) { |
| 975 |
$track_trace_url = WCPOST_Admin::getTrackTraceUrl($order_id, $track_trace); |
| 976 |
$track_trace_link = sprintf( |
| 977 |
'<a href="%s" target="_blank">%s</a>', |
| 978 |
$track_trace_url, |
| 979 |
$track_trace |
| 980 |
); |
| 981 |
} elseif (isset($shipment["shipment"]) && isset($shipment["shipment"]["options"])) { |
| 982 |
$package_type = WCPN_Export::getPackageTypeHuman($shipment["shipment"]["options"]["package_type"]); |
| 983 |
$track_trace_link = "($package_type)"; |
| 984 |
} else { |
| 985 |
$track_trace_link = __("(Unknown)", "woocommerce-postnl"); |
| 986 |
} |
| 987 |
|
| 988 |
echo $track_trace_link; |
| 989 |
} |
| 990 |
|
| 991 |
/** |
| 992 |
* @param array $shipment |
| 993 |
* @param int $order_id |
| 994 |
*/ |
| 995 |
public static function renderStatus(array $shipment, int $order_id): void |
| 996 |
{ |
| 997 |
echo $shipment["status"] ?? "–"; |
| 998 |
|
| 999 |
if (self::shipmentIsStatus($shipment, self::ORDER_STATUS_DELIVERED_AT_RECIPIENT) |
| 1000 |
|| self::shipmentIsStatus($shipment, self::ORDER_STATUS_DELIVERED_READY_FOR_PICKUP) |
| 1001 |
|| self::shipmentIsStatus($shipment, self::ORDER_STATUS_DELIVERED_PACKAGE_PICKED_UP) |
| 1002 |
) { |
| 1003 |
$order = WCX::get_order($order_id); |
| 1004 |
// This will be addressed in MY-24881 |
| 1005 |
// $order->update_status('wc-custom-delivered'); |
| 1006 |
} |
| 1007 |
} |
| 1008 |
|
| 1009 |
/** |
| 1010 |
* @param array $shipment |
| 1011 |
* @param int $status |
| 1012 |
* |
| 1013 |
* @return bool |
| 1014 |
*/ |
| 1015 |
public static function shipmentIsStatus(array $shipment, int $status): bool |
| 1016 |
{ |
| 1017 |
return strstr($shipment['status'], (new WCPN_Export())->getShipmentStatusName($status)); |
| 1018 |
} |
| 1019 |
|
| 1020 |
/** |
| 1021 |
* Remove options that aren't allowed and return the edited array. |
| 1022 |
* |
| 1023 |
* @param array $data |
| 1024 |
* @param string $country |
| 1025 |
* |
| 1026 |
* @return mixed |
| 1027 |
*/ |
| 1028 |
private static function removeDisallowedDeliveryOptions(array $data, string $country): array |
| 1029 |
{ |
| 1030 |
$data['package_type'] = $data['package_type'] ?? AbstractConsignment::DEFAULT_PACKAGE_TYPE_NAME; |
| 1031 |
$isHomeCountry = WCPN_Data::isHomeCountry($country); |
| 1032 |
$isEuCountry = WCPN_Country_Codes::isEuCountry($country); |
| 1033 |
|
| 1034 |
if (! $isHomeCountry) { |
| 1035 |
$data['package_type'] = AbstractConsignment::DEFAULT_PACKAGE_TYPE_NAME; |
| 1036 |
} |
| 1037 |
|
| 1038 |
$isPackage = AbstractConsignment::PACKAGE_TYPE_PACKAGE_NAME === $data['package_type']; |
| 1039 |
|
| 1040 |
if (! $isHomeCountry || ! $isPackage) { |
| 1041 |
$data['shipment_options']['age_check'] = false; |
| 1042 |
$data['shipment_options']['return_shipment'] = false; |
| 1043 |
$data['shipment_options']['insured'] = false; |
| 1044 |
$data['shipment_options']['insured_amount'] = 0; |
| 1045 |
|
| 1046 |
$data['extra_options']['collo_amount'] = 1; |
| 1047 |
} |
| 1048 |
|
| 1049 |
return $data; |
| 1050 |
} |
| 1051 |
} |
| 1052 |
|
| 1053 |
return new WCPOST_Admin(); |
| 1054 |
|