Changeset 3260902
- Timestamp:
- 03/24/2025 02:50:09 PM (12 months ago)
- Location:
- ali2woo-lite/trunk
- Files:
-
- 24 edited
-
alinext-lite.php (modified) (1 diff)
-
assets/js/admin_script.js (modified) (10 diffs)
-
changelog.txt (modified) (1 diff)
-
di-config.php (modified) (2 diffs)
-
includes/classes/connector/AliexpressDefaultConnector.php (modified) (1 diff)
-
includes/classes/controller/FrontendInitController.php (modified) (1 diff)
-
includes/classes/controller/ImportAjaxController.php (modified) (6 diffs)
-
includes/classes/controller/OrderFulfillmentController.php (modified) (3 diffs)
-
includes/classes/controller/WooCommerceProductListController.php (modified) (8 diffs)
-
includes/classes/dto/ShippingItemDto.php (modified) (2 diffs)
-
includes/classes/factory/ExternalOrderFactory.php (modified) (1 diff)
-
includes/classes/model/Aliexpress.php (modified) (5 diffs)
-
includes/classes/model/Woocommerce.php (modified) (10 diffs)
-
includes/classes/service/ImportedProductService.php (modified) (1 diff)
-
includes/classes/service/OrderFulfillmentService.php (modified) (3 diffs)
-
includes/classes/service/ProductService.php (modified) (4 diffs)
-
includes/classes/service/ProductShippingDataService.php (modified) (3 diffs)
-
includes/classes/service/WoocommerceService.php (modified) (5 diffs)
-
includes/classes/utils/Helper.php (modified) (7 diffs)
-
includes/classes/utils/Utils.php (modified) (1 diff)
-
includes/libs/json_api/controllers/core.php (modified) (5 diffs)
-
readme.txt (modified) (1 diff)
-
view/import.php (modified) (1 diff)
-
view/order-fulfillment/partials/fulfillment_order_items.php (modified) (3 diffs)
Legend:
- Unmodified
- Added
- Removed
-
ali2woo-lite/trunk/alinext-lite.php
r3254982 r3260902 6 6 Text Domain: ali2woo 7 7 Domain Path: /languages 8 Version: 3.5. 48 Version: 3.5.5 9 9 Author: Dropshipping Guru 10 10 Author URI: https://ali2woo.com/dropshipping-plugin/?utm_source=lite&utm_medium=author&utm_campaign=alinext-lite -
ali2woo-lite/trunk/assets/js/admin_script.js
r3254982 r3260902 943 943 .find('.current-shipping-company'); 944 944 945 let options = items.map(item => { 946 const isSelected = item.serviceName === method ? 'selected' : ''; 947 948 return (`<option value="${item.serviceName}" ${isSelected}>` + 949 `${item.company} (${item.time} days, ${item.freightAmount.formatedAmount})` + 950 `</option>`).toString(); 951 }).join(''); 945 let options = '<option>Shipping unavailable for this address</option>'; 946 947 if (items && method) { 948 options = items.map(item => { 949 const isSelected = item.serviceName === method ? 'selected' : ''; 950 951 return (`<option value="${item.serviceName}" ${isSelected}>` + 952 `${item.company} (${item.time} days, ${item.freightAmount.formatedAmount})` + 953 `</option>`).toString(); 954 }).join(''); 955 } 952 956 953 957 $select.html(options).trigger('change'); … … 960 964 961 965 const onSelectCallback = function (product_id, variation_key, items, country_from, country_to, method) { 962 if (method && items) {963 $btn.data('country_from', country_from);964 $btn.data('country_to', country_to);965 $btn.data('shipping_method', method);966 $btn.data('variation_key', variation_key); 967 966 $btn.data('country_from', country_from); 967 $btn.data('country_to', country_to); 968 $btn.data('shipping_method', method); 969 $btn.data('variation_key', variation_key); 970 971 if (items) { 968 972 let cost; 969 973 let selected_item; 970 974 971 975 $.each(items, function (i, item) { 972 if (item.serviceName === method ) {976 if (item.serviceName === method || !method) { 973 977 cost = item.previewFreightAmount ? 974 978 item.previewFreightAmount.value : 975 979 item.freightAmount.value 976 980 selected_item = item; 981 return; 977 982 } 978 983 }); … … 2118 2123 2119 2124 function prepareProductUpdateData(product, updateDescription = false) { 2120 varupdateData = {2125 const updateData = { 2121 2126 title: $(product).find('input.title').val(), 2122 2127 sku: $(product).find('input.sku').val(), … … 2161 2166 2162 2167 $('.a2wl-content .product input.attr-name').change(function () { 2163 varproduct = $(this).parents('.product');2168 let product = $(this).parents('.product'); 2164 2169 a2wl_update_product($(product).attr('data-id'), prepareProductUpdateData(product)); 2165 2170 }); … … 2170 2175 }); 2171 2176 2172 $('.a2wl-content .variants-table .var_data input[type="text"]').change(function () { 2173 var product = $(this).parents('.product'); 2177 const importListAPI = function() { 2178 function updateProductAttributes(productNode) { 2179 let variations = []; 2180 $(productNode).find('.variants-table tbody tr').each(function () { 2181 const variation = { 2182 variation_id: $(this).attr('data-id'), 2183 sku: $(this).find('.sku').val(), 2184 quantity: $(this).find('.quantity').val(), 2185 price: $(this).find('.price').val(), 2186 regular_price: $(this).find('.regular_price').val(), 2187 attributes: [] 2188 }; 2189 $(this).find('input.attr').each(function () { 2190 variation.attributes.push({ id: $(this).attr('data-id'), value: $(this).val() }); 2191 }); 2192 variations.push(variation); 2193 }); 2194 2195 a2wl_update_product($(productNode).attr('data-id'), { variations }, response => { 2196 if (response.state === "ok" && response.new_attr_mapping) { 2197 $.each(response.new_attr_mapping, function (i, a) { 2198 $('[data-id="' + a.variation_id + '"] input[data-id="' + a.old_attr_id + '"]').attr('data-id', a.new_attr_id); 2199 }); 2200 } 2201 }); 2202 2203 } 2204 2205 return { 2206 updateProductAttributes: updateProductAttributes, 2207 } 2208 }(); 2209 2210 $('.a2wl-content .variants-table .var_data input[type="text"]').on('change', function () { 2211 let product = $(this).parents('.product'); 2174 2212 a2wl_calc_profit(jQuery(product).attr('data-id')); 2175 2176 let variations = []; 2177 $(product).find('.variants-table tbody tr').each(function () { 2178 var variation = { variation_id: $(this).attr('data-id'), sku: $(this).find('.sku').val(), quantity: $(this).find('.quantity').val(), price: $(this).find('.price').val(), regular_price: $(this).find('.regular_price').val(), attributes: [] }; 2179 $(this).find('input.attr').each(function () { 2180 variation.attributes.push({ id: $(this).attr('data-id'), value: $(this).val() }); 2181 }); 2182 variations.push(variation); 2183 }); 2184 a2wl_update_product($(product).attr('data-id'), { variations }, response => { 2185 if (response.state === "ok" && response.new_attr_mapping) { 2186 $.each(response.new_attr_mapping, function (i, a) { 2187 $('[data-id="' + a.variation_id + '"] input[data-id="' + a.old_attr_id + '"]').attr('data-id', a.new_attr_id); 2188 }); 2189 } 2190 }); 2213 importListAPI.updateProductAttributes(product); 2191 2214 }); 2192 2215 … … 2195 2218 }); 2196 2219 2197 $('.a2wl-content .price-edit-selector .dropdown-menu a').click(function () { 2220 $('.a2wl-content .price-edit-selector .dropdown-menu a').on('click', function (event) { 2221 event.preventDefault(); 2222 2198 2223 if ($(this).hasClass('set-new-value')) { 2199 2224 $(this).parents('.price-edit-selector').find('.price-box-top input[type="text"]').attr('placeholder', 'Enter Value'); … … 2217 2242 const attr_id = $(this).parents('td').attr('data-attr-id'); 2218 2243 2219 $(".a2wl-rename-attrs-modal") 2244 const $modal = $(".a2wl-rename-attrs-modal"); 2245 $modal 2220 2246 .addClass('opened') 2221 .data('attr_id', attr_id) 2222 .data('product', $(this).closest('.product')); 2247 .data({ 2248 'attr_id': attr_id, 2249 'product': $(this).closest('.product') 2250 }); 2223 2251 2224 2252 $attrsTable.empty(); 2225 $(this).parents('.variants-table').find('td[data-attr-id="' + attr_id + '"] input').each(function () { 2226 const val = $(this).val(); 2227 const attr_name_id = $(this).data('id'); 2228 2229 if (val && $attrsTable.find('input[name="' + attr_name_id + '"]').length === 0) { 2230 $attrsTable.append('<tr class="a2wl-rename-attrs-modal__row"><td class="a2wl-rename-attrs-modal__name">'+val+'</td><td class="a2wl-rename-attrs-modal__new-name" data-id="'+attr_name_id+'"><input type="text" name="'+attr_name_id+'" placeholder="'+a2wl_common_data.lang.attr_new_name+'"></td></tr>') 2231 } 2232 }); 2253 2254 $(this).closest('.variants-table').find(`td[data-attr-id="${attr_id}"] input`).each( 2255 function () { 2256 const val = $(this).val(); 2257 const attr_name_id = $(this).data('id'); 2258 2259 if (val && !$attrsTable.find(`input[name="${attr_name_id}"]`).length) { 2260 const newRow = 2261 `<tr class="a2wl-rename-attrs-modal__row"> 2262 <td class="a2wl-rename-attrs-modal__name">${val}</td> 2263 <td class="a2wl-rename-attrs-modal__new-name" data-id="${attr_name_id}"> 2264 <input type="text" name="${attr_name_id}" placeholder="${a2wl_common_data.lang.attr_new_name}"> 2265 </td> 2266 </tr>`; 2267 $attrsTable.append(newRow); 2268 } 2269 } 2270 ); 2233 2271 2234 2272 $('.price-edit-selector').find('.price-box-top').hide(); 2235 2236 return;2237 2273 } 2238 2274 … … 2263 2299 $attrInputs.each(function () { 2264 2300 const attr_name_id = $(this).data('id'); 2265 const value = $(this).val(); 2266 2267 oldAttrs[attr_name_id] = value; 2301 oldAttrs[attr_name_id] = $(this).val(); 2268 2302 }); 2269 2303 … … 2311 2345 }); 2312 2346 2313 2314 2347 //save 2315 2348 if (!duplicatesKeys.length) { … … 2320 2353 $('.a2wl-rename-attrs-modal').removeClass('opened'); 2321 2354 } 2355 2356 importListAPI.updateProductAttributes($product); 2322 2357 }); 2323 2358 -
ali2woo-lite/trunk/changelog.txt
r3254982 r3260902 349 349 * Fix bug with non-Latin characters in the attribute name feature of the import list 350 350 351 3.5.5 352 * Improved the attribute renaming feature in the Import List. Changes are now preserved after reloading the Import List 353 * Resolved several issues with the product import functionality that arose from recent refactoring. 354 -
ali2woo-lite/trunk/di-config.php
r3254982 r3260902 281 281 get(ProductService::class), 282 282 get(WoocommerceService::class), 283 get(Review::class), 284 get(Woocommerce::class), 285 get(PriceFormulaService::class), 283 286 ), 284 287 'AliNext_Lite\SearchPageController' => create(SearchPageController::class) … … 316 319 get(Woocommerce::class), 317 320 get(ProductService::class), 321 get(Aliexpress::class), 322 get(PriceFormulaService::class) 318 323 ), 319 324 ]; -
ali2woo-lite/trunk/includes/classes/connector/AliexpressDefaultConnector.php
r3250609 r3260902 141 141 'quantity' => $quantity, 142 142 'country_code' => $country_code, 143 'country_code_from' => $country_code_from, 143 144 'extra_data' => $extra_data, 144 145 ]; -
ali2woo-lite/trunk/includes/classes/controller/FrontendInitController.php
r3254982 r3260902 159 159 } 160 160 161 $countryFromCode = 'CN';162 163 161 try { 162 $countryFromCode = $this->WoocommerceService->getShippingFromByProduct($WC_ProductOrVariation); 164 163 $importedProduct = $this->WoocommerceService->updateProductShippingItems( 165 164 $WC_ProductOrVariation, -
ali2woo-lite/trunk/includes/classes/controller/ImportAjaxController.php
r3254982 r3260902 929 929 if (get_setting('allow_product_duplication') || !$post_id) { 930 930 $params = empty($_POST['apd']) ? array() : array('data' => array('apd' => json_decode(stripslashes($_POST['apd'])))); 931 $res = $this-> ProductService->loadProductWithShippingInfo($_POST['id'], $params);931 $res = $this->AliexpressModel->load_product($_POST['id'], $params); 932 932 if ($res['state'] !== 'error') { 933 933 $product = array_replace_recursive($product, $res['product']); … … 1082 1082 //todo: Here we take product countries to pass as parameters 1083 1083 //need to move this logic to WoocommerceService::updateProductShippingInfo() 1084 $product_country_from = !empty($importedProduct[ImportedProductService::FIELD_COUNTRY_FROM]) ?1084 /* $product_country_from = !empty($importedProduct[ImportedProductService::FIELD_COUNTRY_FROM]) ? 1085 1085 $importedProduct[ImportedProductService::FIELD_COUNTRY_FROM] : 1086 'CN'; 1086 'CN';*/ 1087 1087 1088 1088 $product_country_to = !empty($importedProduct[ImportedProductService::FIELD_COUNTRY_TO]) … … 1091 1091 1092 1092 $countryToCode = $_POST['country_to'] ?? $product_country_to; 1093 $countryFromCode = !empty($_POST['country_from']) ? $_POST['country_from'] : $product_country_from; 1093 // $countryFromCode = !empty($_POST['country_from']) ? $_POST['country_from'] : $product_country_from; 1094 $countryFromCode = $this->WoocommerceService->getShippingFromByProduct($WC_ProductOrVariation); 1094 1095 1095 1096 //todo: $externalSkuId should be update if the product variations are changed … … 1211 1212 1212 1213 $countryToCode = $_POST['country_to'] ?? $product_country_to; 1213 $countryFromCode = !empty($_POST['country_from']) ? $_POST['country_from'] : $product_country_from; 1214 // $countryFromCode = !empty($_POST['country_from']) ? $_POST['country_from'] : $product_country_from; 1215 1216 $countryFromCode = $this->WoocommerceService->getShippingFromByProduct($WC_ProductOrVariation); 1214 1217 1215 1218 try { 1216 1219 $importedProduct = $this->WoocommerceService->updateProductShippingInfo( 1217 $WC_ProductOrVariation, 1218 $countryToCode, 1219 $countryFromCode 1220 $WC_ProductOrVariation, $countryToCode, 1220 1221 ); 1221 1222 … … 1288 1289 1289 1290 $countryToCode = $_POST['country_to'] ?? $product_country_to; 1290 $countryFromCode = !empty($_POST['country_from']) ? $_POST['country_from'] : $product_country_from; 1291 $countryFromCode = $this->ProductService->getShippingFromByExternalSkuId( 1292 $importedProduct, $externalSkuId 1293 ); 1291 1294 1292 1295 $countryCode = ProductShippingData::meta_key($countryFromCode, $countryToCode); … … 1443 1446 } 1444 1447 1445 // a2wl_error_log('Aliexpress categories from server: ' . print_r($productCategoryInfo, true));1446 1447 1448 $insertedCategories = []; 1448 1449 -
ali2woo-lite/trunk/includes/classes/controller/OrderFulfillmentController.php
r3254982 r3260902 517 517 <?php endif; ?> 518 518 */ ?> 519 <button class="btn btn-default modal-close" type="button"><?php esc_html_e('Close');?></button>519 <button class="btn btn-default modal-close" type="button"><?php esc_html_e('Close');?></button> 520 520 </div> 521 521 </div> … … 537 537 } 538 538 539 /** 540 * On order fulfillment popup loading 541 * @return void 542 */ 539 543 public function ajax_load_fulfillment_orders_html(): void 540 544 { … … 580 584 $this->model_put("ProductShippingDataService", $this->ProductShippingDataService); 581 585 $this->model_put("ImportedProductServiceFactory", $this->ImportedProductServiceFactory); 582 583 //$ProductShippingDataService584 586 585 587 foreach ($orders_data as $order_data) { -
ali2woo-lite/trunk/includes/classes/controller/WooCommerceProductListController.php
r3254982 r3260902 18 18 protected ProductService $ProductService; 19 19 protected WoocommerceService $WoocommerceService; 20 protected Review $ReviewModel; 21 protected Woocommerce $WoocommerceModel; 22 protected PriceFormulaService $PriceFormulaService; 20 23 21 24 private $bulk_actions = []; … … 24 27 public function __construct( 25 28 ProductService $ProductService, 26 WoocommerceService $WoocommerceService 29 WoocommerceService $WoocommerceService, 30 Review $ReviewModel, 31 Woocommerce $WoocommerceModel, 32 PriceFormulaService $PriceFormulaService 27 33 ) { 28 34 parent::__construct(); … … 30 36 $this->ProductService = $ProductService; 31 37 $this->WoocommerceService = $WoocommerceService; 38 $this->ReviewModel = $ReviewModel; 39 $this->WoocommerceModel = $WoocommerceModel; 40 $this->PriceFormulaService = $PriceFormulaService; 32 41 33 42 add_action('admin_footer-edit.php', array($this, 'scripts')); … … 271 280 a2wl_init_error_handler(); 272 281 try { 273 /** @var $woocommerce_model Woocommerce */274 $woocommerce_model = A2WL()->getDI()->get('AliNext_Lite\Woocommerce');275 $PriceFormulaService = A2WL()->getDI()->get('AliNext_Lite\PriceFormulaService');276 277 282 $ids = isset($_POST['ids']) ? (is_array($_POST['ids']) ? $_POST['ids'] : array($_POST['ids'])) : array(); 278 283 … … 319 324 foreach ($res['products'] as $product) { 320 325 $product = array_replace_recursive($products[strval($product[ImportedProductService::FIELD_EXTERNAL_PRODUCT_ID])], $product); 321 $product = $ PriceFormulaService->applyFormula($product);322 $ woocommerce_model->upd_product($product['post_id'], $product, array('manual_update' => 1));326 $product = $this->PriceFormulaService->applyFormula($product); 327 $this->WoocommerceModel->upd_product($product['post_id'], $product, array('manual_update' => 1)); 323 328 } 324 329 … … 347 352 a2wl_init_error_handler(); 348 353 try { 349 /** @var $woocommerce_model Woocommerce */350 $woocommerce_model = A2WL()->getDI()->get('AliNext_Lite\Woocommerce');351 352 354 $ids = isset($_POST['ids']) ? (is_array($_POST['ids']) ? $_POST['ids'] : array($_POST['ids'])) : array(); 353 355 354 356 $error = 0; 355 357 foreach ($ids as $post_id) { 356 $external_id = $ woocommerce_model->get_product_external_id($post_id);358 $external_id = $this->WoocommerceModel->get_product_external_id($post_id); 357 359 if ($external_id) { 358 360 try { 359 $reviews_model = new Review(); 360 $reviews_model->load($post_id, true); 361 $this->ReviewModel->load($post_id, true); 361 362 } catch (Throwable $e) { 362 a2wl_print_throwable($e);363 $error++;364 } catch (\Exception $e) {365 363 a2wl_print_throwable($e); 366 364 $error++; … … 371 369 } 372 370 373 $result = array("state" => "ok", "update_state" => array('ok' => count($ids), 'error' => 0)); 371 $result = [ 372 "state" => "ok", 373 "update_state" => [ 374 'ok' => count($ids), 375 'error' => $error 376 ] 377 ]; 374 378 } catch (Throwable $e) { 375 379 a2wl_print_throwable($e); … … 393 397 394 398 if (!empty($_POST['post_id'])) { 395 /** @var $woocommerce_model Woocommerce */ 396 $woocommerce_model = A2WL()->getDI()->get('AliNext_Lite\Woocommerce'); 397 $id = $woocommerce_model->get_product_external_id($_POST['post_id']); 399 $id = $this->WoocommerceModel->get_product_external_id($_POST['post_id']); 398 400 if ($id) { 399 401 $result = ResultBuilder::buildOk(array('id' => $id)); -
ali2woo-lite/trunk/includes/classes/dto/ShippingItemDto.php
r3250609 r3260902 12 12 { 13 13 public function __construct( 14 private string $methodName, private float $cost 14 private string $methodName, 15 private float $cost, 16 private string $companyName, 17 private string $days, /* example 20 or 15-30 */ 18 private bool $hasTracking, 15 19 ) {} 16 20 … … 24 28 return $this->cost; 25 29 } 30 31 public function getCompanyName(): string 32 { 33 return $this->companyName; 34 } 35 36 public function getDays(): string 37 { 38 return $this->days; 39 } 40 41 public function hasTracking(): bool 42 { 43 return $this->hasTracking; 44 } 26 45 } -
ali2woo-lite/trunk/includes/classes/factory/ExternalOrderFactory.php
r3250609 r3260902 203 203 $productType = $orderItem->get_product()->get_type(); 204 204 205 if ($productType == 'variation') {205 if ($productType === 'variation') { 206 206 $variationId = $orderItem->get_variation_id(); 207 207 $WC_Product_Variation = new WC_Product_Variation($variationId); -
ali2woo-lite/trunk/includes/classes/model/Aliexpress.php
r3254982 r3260902 9 9 namespace AliNext_Lite;; 10 10 11 use DOMDocument; 11 12 use Throwable; 12 13 … … 461 462 ); 462 463 463 /* error_log('shipping info:');464 error_log(print_r($result, true));465 error_log('externalProductId: ' . $externalProductId);466 error_log('extraData: ' . $extraData);467 error_log('externalSkuId: ' . $externalSkuId);*/468 469 464 if (!empty($result['state']) && $result['state'] !== 'error') { 470 465 return $result['items']; … … 489 484 490 485 if (function_exists('mb_convert_encoding')) { 491 $html = trim(mb_convert_encoding($html, 'HTML-ENTITIES', 'UTF-8'));486 $html = htmlspecialchars($html, ENT_QUOTES | ENT_HTML5, 'UTF-8'); 492 487 } else { 493 $html = htmlspecialchars_decode(utf8_decode(htmlentities($html, ENT_COMPAT, 'UTF-8', false))); 488 $html = htmlspecialchars_decode( 489 utf8_decode(htmlentities($html, ENT_COMPAT, 'UTF-8', false)) 490 ); 494 491 } 495 492 … … 499 496 500 497 if ($html && class_exists('\DOMDocument')) { 501 $dom = new \DOMDocument();498 $dom = new DOMDocument(); 502 499 @$dom->loadHTML($html); 503 500 $dom->formatOutput = true; … … 818 815 private function normalizeLoadedShippingInfo(array $product): array 819 816 { 820 $hasShippingInfo = isset($product['shipping_info']['items']) &&817 $hasShippingInfo = !empty($product['shipping_info']['items']) && 821 818 is_array($product['shipping_info']['items']); 822 819 -
ali2woo-lite/trunk/includes/classes/model/Woocommerce.php
r3254982 r3260902 253 253 ], 254 254 '_a2w_disable_sync' => 0, 255 '_a2w_disable_var_price_change' => isset($product['disable_var_price_change']) && $product['disable_var_price_change'] ? 1 : 0, 256 '_a2w_disable_var_quantity_change' => isset($product['disable_var_quantity_change']) && $product['disable_var_quantity_change'] ? 1 : 0, 257 '_a2w_disable_add_new_variants' => isset($product['disable_add_new_variants']) && $product['disable_add_new_variants'] ? 1 : 0, 255 '_a2w_disable_var_price_change' => 256 isset($product['disable_var_price_change']) && $product['disable_var_price_change'] ? 1 : 0, 257 '_a2w_disable_var_quantity_change' => 258 isset($product['disable_var_quantity_change']) && $product['disable_var_quantity_change'] ? 1 : 0, 259 '_a2w_disable_add_new_variants' => 260 isset($product['disable_add_new_variants']) && $product['disable_add_new_variants'] ? 1 : 0, 258 261 '_a2w_orders_count' => (!empty($product['ordersCount']) ? intval($product['ordersCount']) : 0), 259 262 ImportedProductService::KEY_VIDEO_DATA => !empty($product['video']) ? $product['video'] : '', 260 '_a2w_import_lang' => !empty($product['import_lang']) ? $product['import_lang'] : AliexpressLocalizator::getInstance()->language, 263 '_a2w_import_lang' => 264 !empty($product['import_lang']) ? $product['import_lang'] : 265 AliexpressLocalizator::getInstance()->language, 261 266 ], 262 267 ]; … … 382 387 383 388 // set default shipping country from 384 if ($first_ava_var && !empty($first_ava_var['country_code'])) { 385 update_post_meta($product_id, '_a2w_country_code', $first_ava_var['country_code']); 389 if ($first_ava_var && !empty($first_ava_var[ImportedProductService::FIELD_COUNTRY_CODE])) { 390 update_post_meta( 391 $product_id, 392 ImportedProductService::KEY_COUNTRY_CODE, 393 $first_ava_var[ImportedProductService::FIELD_COUNTRY_CODE] 394 ); 386 395 } else if (isset($product['local_seller_tag']) && strlen($product['local_seller_tag']) == 2) { 387 update_post_meta($product_id, '_a2w_country_code', $product['local_seller_tag']); 396 update_post_meta( 397 $product_id, ImportedProductService::KEY_COUNTRY_CODE, $product['local_seller_tag'] 398 ); 388 399 } 389 400 … … 396 407 if (get_option('woocommerce_manage_stock', 'no') === 'yes') { 397 408 update_post_meta($product_id, '_manage_stock', 'yes'); 398 update_post_meta($product_id, '_stock_status', $total_quantity ? 'instock' : 'outofstock'); 409 update_post_meta( 410 $product_id, '_stock_status', $total_quantity ? 'instock' : 'outofstock' 411 ); 399 412 update_post_meta($product_id, '_stock', $total_quantity); 400 413 } else { … … 404 417 } 405 418 406 if (isset($product['attribute']) 407 && $product['attribute'] 408 && !get_setting('not_import_attributes', false) 419 if (!empty($product['attribute']) && !get_setting('not_import_attributes', false) 409 420 && (!$override_product || $override_title_description) 410 421 ) { … … 795 806 796 807 // set default shipping country from 797 if ($first_ava_var && !empty($first_ava_var['country_code'])) { 798 $wc_product->update_meta_data('_a2w_country_code', $first_ava_var['country_code']); 808 if ($first_ava_var && !empty($first_ava_var[ImportedProductService::FIELD_COUNTRY_CODE])) { 809 $wc_product->update_meta_data( 810 ImportedProductService::KEY_COUNTRY_CODE, 811 $first_ava_var[ImportedProductService::FIELD_COUNTRY_CODE] 812 ); 799 813 } else if (isset($product['local_seller_tag']) && strlen($product['local_seller_tag']) == 2) { 800 $wc_product->update_meta_data( '_a2w_country_code', $product['local_seller_tag']);814 $wc_product->update_meta_data(ImportedProductService::KEY_COUNTRY_CODE, $product['local_seller_tag']); 801 815 } 802 816 … … 960 974 961 975 if (function_exists('mb_convert_encoding')) { 962 $html = trim(mb_convert_encoding($html, 'HTML-ENTITIES', 'UTF-8'));976 $html = htmlspecialchars($html, ENT_QUOTES | ENT_HTML5, 'UTF-8'); 963 977 } else { 964 $html = htmlspecialchars_decode(utf8_decode(htmlentities($html, ENT_COMPAT, 'UTF-8', false))); 978 $html = htmlspecialchars_decode( 979 utf8_decode(htmlentities($html, ENT_COMPAT, 'UTF-8', false)) 980 ); 965 981 } 966 982 … … 1180 1196 } 1181 1197 1182 private function set_attributes( $product_id, $attributes)1198 private function set_attributes(int $product_id, array $attributes): void 1183 1199 { 1184 1200 if (defined('A2WL_IMPORT_EXTENDED_ATTRIBUTE')) { … … 1193 1209 $this->helper->set_woocommerce_attributes($product_id, $attributes); 1194 1210 } else { 1195 $tmp_product_attr = array();1211 $tmp_product_attr = []; 1196 1212 foreach ($attributes as $attr) { 1197 1213 if (!isset($tmp_product_attr[$attr['name']])) { 1198 $tmp_product_attr[$attr['name']] = is_array($attr['value']) ? $attr['value'] : array($attr['value']);1214 $tmp_product_attr[$attr['name']] = is_array($attr['value']) ? $attr['value'] : [$attr['value']]; 1199 1215 } else { 1200 $tmp_product_attr[$attr['name']] = array_merge($tmp_product_attr[$attr['name']], is_array($attr['value']) ? $attr['value'] : array($attr['value'])); 1201 } 1202 } 1203 1204 $product_attributes = array(); 1216 $tmp_product_attr[$attr['name']] = array_merge( 1217 $tmp_product_attr[$attr['name']], 1218 is_array($attr['value']) ? $attr['value'] : [$attr['value']] 1219 ); 1220 } 1221 } 1222 1223 $product_attributes = []; 1205 1224 foreach ($tmp_product_attr as $name => $value) { 1206 $product_attributes[str_replace(' ', '-', $name)] = array(1225 $product_attributes[str_replace(' ', '-', $name)] = [ 1207 1226 'name' => $name, 1208 1227 'value' => implode(', ', $value), … … 1211 1230 'is_variation' => 0, 1212 1231 'is_taxonomy' => 0, 1213 );1232 ]; 1214 1233 } 1215 1234 … … 1921 1940 } 1922 1941 1923 if (!empty($variation['country_code'])) { 1924 update_post_meta($variation_id, '_a2w_country_code', $variation['country_code']); 1942 if (!empty($variation[ImportedProductService::FIELD_COUNTRY_CODE])) { 1943 update_post_meta( 1944 $variation_id, 1945 ImportedProductService::KEY_COUNTRY_CODE, 1946 $variation[ImportedProductService::FIELD_COUNTRY_CODE] 1947 ); 1925 1948 } else if (isset($product['local_seller_tag']) && strlen($product['local_seller_tag']) == 2) { 1926 update_post_meta($variation_id, '_a2w_country_code', $product['local_seller_tag']); 1949 update_post_meta( 1950 $variation_id, ImportedProductService::KEY_COUNTRY_CODE, $product['local_seller_tag'] 1951 ); 1927 1952 } 1928 1953 -
ali2woo-lite/trunk/includes/classes/service/ImportedProductService.php
r3254982 r3260902 33 33 public const FIELD_EXTERNAL_SKU_ID = 'skuId'; 34 34 public const FIELD_EXTERNAL_PRODUCT_ID = 'id'; 35 public const FIELD_COUNTRY_CODE = 'country_code'; 35 36 36 37 private array $shouldShowVideoTabStates = [ -
ali2woo-lite/trunk/includes/classes/service/OrderFulfillmentService.php
r3254982 r3260902 281 281 $quantity = $item->get_quantity(); 282 282 283 $countryFromCode = 'CN';283 $countryFromCode = $this->WoocommerceService->getShippingFromByProduct($WC_Product); 284 284 285 285 $importedProduct = $this->WoocommerceService … … 297 297 $current_delivery_time = '-'; 298 298 $current_shipping_cost = ''; 299 $shipping_meta_data = $item->get_meta(Shipping::get_order_item_shipping_meta_key()); 299 300 if ($ShippingItemDto->getMethodName()) { 301 $current_shipping_company = $ShippingItemDto->getMethodName(); 302 $current_shipping_cost = $ShippingItemDto->getCost(); 303 $current_delivery_time = $ShippingItemDto->getDays(); 304 } 305 306 /* $shipping_meta_data = $item->get_meta(Shipping::get_order_item_shipping_meta_key()); 300 307 301 308 if ($shipping_meta_data) { … … 305 312 $current_shipping_cost = $shipping_meta_data['shipping_cost']; 306 313 } 307 $current_shipping_company = $current_shipping_company ?: $ShippingItemDto->getMethodName(); 314 $current_shipping_company = $current_shipping_company ?: $ShippingItemDto->getMethodName();*/ 308 315 309 316 $wpml_product_id = $wpml_variation_id = ''; -
ali2woo-lite/trunk/includes/classes/service/ProductService.php
r3254982 r3260902 180 180 if (isset($product['sku_products'])) { 181 181 foreach ($product['sku_products']['variations'] as $var) { 182 if (!empty($var['country_code'])) { 183 $shipping_from_country_list[$var['country_code']] = $var['country_code']; 182 if (!empty($var[ImportedProductService::FIELD_COUNTRY_CODE])) { 183 $shipping_from_country_list[$var[ImportedProductService::FIELD_COUNTRY_CODE]] = 184 $var[ImportedProductService::FIELD_COUNTRY_CODE]; 184 185 } 185 186 /* if ($var['id'] === $variationExternalId) { … … 230 231 231 232 return $product; 233 } 234 235 /** 236 * @param array $product 237 * @param null|string $externalSkuId 238 * @return string 239 */ 240 public function getShippingFromByExternalSkuId(array $product, ?string $externalSkuId = null): string 241 { 242 if (!$externalSkuId) { 243 return 'CN'; 244 } 245 246 foreach ($product['sku_products']['variations'] as $variation) { 247 if ($variation['skuId'] === $externalSkuId) { 248 return $variation[ImportedProductService::FIELD_COUNTRY_CODE] ?? 'CN'; 249 } 250 } 251 252 return 'CN'; 232 253 } 233 254 … … 294 315 } 295 316 317 /** 318 * todo: need to use hasTracking and companyName too in code which calls findDefaultFromShippingItems 319 */ 296 320 $shipping_cost = 0; 321 $shippingTime = ''; 322 $hasTracking = false; 323 $companyName = ''; 297 324 foreach ($shippingItems as $shippingItem) { 298 325 if ($shippingItem['serviceName'] == $default_method) { 326 $shippingTime = $shippingItem['time'] ?? ''; 327 $hasTracking = isset($shippingItem['tracking']) && $shippingItem['tracking']; 328 $companyName = $shippingItem['company'] ?? $shippingItem['serviceName']; 299 329 $shipping_cost = $shippingItem['previewFreightAmount']['value'] ?? $shippingItem['freightAmount']['value']; 300 330 $shipping_cost = apply_filters('wcml_raw_price_amount', $shipping_cost, $current_currency); … … 302 332 } 303 333 304 return new ShippingItemDto($default_method, $shipping_cost); 334 return new ShippingItemDto( 335 $default_method, $shipping_cost, $companyName, $shippingTime, $hasTracking 336 ); 305 337 } 306 338 -
ali2woo-lite/trunk/includes/classes/service/ProductShippingDataService.php
r3254982 r3260902 11 11 class ProductShippingDataService 12 12 { 13 14 public const META_COUNTRY_CODE = '_a2w_country_code';15 13 16 14 protected ProductShippingDataRepository $ProductShippingDataRepository; … … 82 80 "ON (pm.post_id=p.ID AND pm.meta_key=%s) WHERE p.post_parent=%d AND p.post_type=%s"; 83 81 84 $query = $wpdb->prepare($query, self::META_COUNTRY_CODE, $productId, 'product_variation');82 $query = $wpdb->prepare($query,ImportedProductService::KEY_COUNTRY_CODE, $productId, 'product_variation'); 85 83 $countryFromList = $wpdb->get_col($query); 86 84 … … 88 86 $query = "SELECT DISTINCT pm.meta_value FROM {$wpdb->postmeta} pm WHERE pm.post_id=%d AND pm.meta_key=%s"; 89 87 90 $query = $wpdb->prepare($query, $productId, self::META_COUNTRY_CODE);88 $query = $wpdb->prepare($query, $productId, ImportedProductService::KEY_COUNTRY_CODE); 91 89 $countryFromList = $wpdb->get_col($query); 92 90 } -
ali2woo-lite/trunk/includes/classes/service/WoocommerceService.php
r3254982 r3260902 40 40 */ 41 41 public function getProductShippingInfo( 42 WC_Product $WC_ProductOrVariation, 43 ?string $countryToCode, string $countryFromCode = 'CN', int $quantity = 1, 42 WC_Product $WC_ProductOrVariation, ?string $countryToCode, int $quantity = 1, 44 43 ): array { 45 44 $ImportedProductService = $this->ImportedProductServiceFactory … … 54 53 return $this->ProductService->updateProductShippingInfo( 55 54 $importedProduct, 56 $ countryFromCode,55 $ImportedProductService->getShippingFromCountryCode(), 57 56 $countryToCode, 58 57 $ImportedProductService->getExternalSkuId(), … … 68 67 */ 69 68 public function updateProductShippingInfo( 70 WC_Product $WC_ProductOrVariation, 71 ?string $countryToCode, string $countryFromCode = 'CN', int $quantity = 1, 69 WC_Product $WC_ProductOrVariation, ?string $countryToCode, int $quantity = 1, 72 70 ): array { 73 71 $importedProduct = $this->getProductShippingInfo( 74 $WC_ProductOrVariation, $countryToCode, $ countryFromCode, $quantity72 $WC_ProductOrVariation, $countryToCode, $quantity 75 73 ); 76 74 … … 86 84 } 87 85 86 public function getShippingFromByProduct(WC_Product $WC_ProductOrVariation): string 87 { 88 $ImportedProductService = $this->ImportedProductServiceFactory 89 ->createFromProduct($WC_ProductOrVariation); 90 91 return $ImportedProductService->getShippingFromCountryCode(); 92 } 93 88 94 /** 89 95 * @throws RepositoryException|ServiceException … … 94 100 ): array { 95 101 $importedProduct = $this->getProductShippingInfo( 96 $WC_ProductOrVariation, $countryToCode, $ countryFromCode, $quantity102 $WC_ProductOrVariation, $countryToCode, $quantity 97 103 ); 98 104 -
ali2woo-lite/trunk/includes/classes/utils/Helper.php
r3250609 r3260902 137 137 } 138 138 139 $taxonomy = $this->cleanTaxonomyName($key); 140 139 141 // get attribute name, label 140 142 $attribute_label = $key; 141 143 142 $attribute_name = $this->cleanTaxonomyName($key, false); 144 //attribute name should be the same as taxonomy just without pa_ 145 $attribute_name = str_replace('pa_', '', $taxonomy); 143 146 144 147 // set attribute type … … 170 173 171 174 // add attribute values if not exist 172 $taxonomy = $this->cleanTaxonomyName($attribute_name);173 175 174 176 $values = is_array($value) ? $value : [$value]; … … 198 200 // add term taxonomy 199 201 $term_id = $wpdb->get_var("SELECT term_id FROM {$wpdb->terms} WHERE name = '" . esc_sql($name) . "'"); 200 $this->db_custom_insert($wpdb->term_taxonomy, array('values' => array('term_id' => $term_id, 'taxonomy' => $taxonomy), 'format' => array('%d', '%s')), true); 202 $this->db_custom_insert( 203 $wpdb->term_taxonomy, 204 [ 205 'values' => ['term_id' => $term_id, 'taxonomy' => $taxonomy], 206 'format' => ['%d', '%s'] 207 ], 208 true 209 ); 201 210 $term_taxonomy_id = $wpdb->insert_id; 202 211 } … … 233 242 // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared 234 243 if (!$wpdb->get_var($checkSql)) { 235 $wpdb->insert($wpdb->term_relationships, array('object_id' => $post_id, 'term_taxonomy_id' => $term_taxonomy_id)); 244 $wpdb->insert( 245 $wpdb->term_relationships, 246 array('object_id' => $post_id, 'term_taxonomy_id' => $term_taxonomy_id) 247 ); 236 248 } 237 249 } … … 491 503 } 492 504 493 public function load_terms($taxonomy) { 494 global $wpdb; 505 public function load_terms(string $taxonomy) { 506 global $wpdb; 507 495 508 $query = "SELECT DISTINCT t.name, t.slug FROM {$wpdb->terms} AS t " . 496 509 "INNER JOIN {$wpdb->term_taxonomy} as tt ON tt.term_id = t.term_id " . 497 510 "WHERE tt.taxonomy = %s"; 498 511 499 return $wpdb->get_results( 500 // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared 501 $wpdb->prepare($query, esc_sql($taxonomy)), OBJECT 502 ); 503 } 504 505 public function db_custom_insert($table, $fields, $ignore = false, $wp_way = false) { 506 global $wpdb; 512 return $wpdb->get_results($wpdb->prepare($query, $taxonomy), OBJECT); 513 } 514 515 public function db_custom_insert(string $table, array $fields, bool $ignore = false, bool $wp_way = false): int 516 { 517 global $wpdb; 518 507 519 if ($wp_way && !$ignore) { 508 520 $wpdb->insert($table, $fields['values'], $fields['format']); 509 521 } else { 510 $formatVals = implode(', ', array_map(array($this, 'prepareForInList'), $fields['format'])); 511 $theVals = array(); 512 foreach ($fields['values'] as $k => $v) 513 $theVals[] = $k; 514 515 $q = "INSERT " . ($ignore ? "IGNORE" : "") . " INTO $table (" . implode(', ', $theVals) . ") VALUES (" . $formatVals . ");"; 516 foreach ($fields['values'] as $kk => $vv) 517 $fields['values']["$kk"] = esc_sql($vv); 518 519 $r = $wpdb->query( 520 // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared 521 $wpdb->prepare(vsprintf($q, $fields['values'])) 522 ); 523 } 522 $columns = []; 523 foreach ($fields['values'] as $k => $v) { 524 $columns[] = $k; 525 } 526 527 $query = "INSERT " . ($ignore ? "IGNORE" : "") . 528 " INTO $table (" . implode(', ', $columns) . ")" . 529 " VALUES (" . implode(', ', $fields['format']) . ");"; 530 531 $valuesForPrepare = array_values($fields['values']); 532 $wpdb->query($wpdb->prepare($query, $valuesForPrepare)); 533 } 534 524 535 return $wpdb->insert_id; 525 536 } 526 537 527 public function prepareForInList($v) { 538 public function prepareForInList($v): string 539 { 528 540 return "'" . $v . "'"; 529 541 } 530 542 531 public function cleanTaxonomyName($value, $withPrefix = true, $checkSize = true) { 532 $ret = $value; 533 543 public function cleanTaxonomyName(string $value, bool $withPrefix = true, bool $checkSize = true): string 544 { 534 545 // Sanitize taxonomy names. Slug format (no spaces, lowercase) - uses sanitize_title 535 546 if ($withPrefix) { … … 539 550 } 540 551 541 if ($checkSize){552 if ($checkSize) { 542 553 // limit to 32 characters (database/ table wp_term_taxonomy/ field taxonomy/ is limited to varchar(32) ) 543 554 if (seems_utf8($ret)) { … … 545 556 if (function_exists('mb_substr')) { 546 557 $ret = mb_substr($ret, 0, $limit_max); 547 } 548 }else{ 558 559 // Ensure generated name doesn't exceed byte length using strlen (because Woocommerce use strlen) 560 while (strlen($ret) > ($withPrefix ? 32 : 28)) { 561 $ret = mb_substr($ret, 0, -1, 'UTF-8'); // remove last character 562 } 563 } 564 } else { 549 565 $limit_max = $withPrefix ? 32 : 29; // 29 = 32 - strlen('pa_') 550 566 $ret = substr($ret, 0, $limit_max); -
ali2woo-lite/trunk/includes/classes/utils/Utils.php
r3250609 r3260902 622 622 foreach ($product['sku_products']['attributes'] as $attr) { 623 623 foreach ($attr['value'] as $attr_val) { 624 if (isset($attr_val[ 'country_code'])) {624 if (isset($attr_val[ImportedProductService::FIELD_COUNTRY_CODE])) { 625 625 $ship_from_attr_name = $attr['name']; 626 if ($attr_val[ 'country_code'] === $default_country) {626 if ($attr_val[ImportedProductService::FIELD_COUNTRY_CODE] === $default_country) { 627 627 $ship_from_attr_value[$default_country] = $attr_val['id']; 628 } else if ($attr_val[ 'country_code'] === $country_from) {628 } else if ($attr_val[ImportedProductService::FIELD_COUNTRY_CODE] === $country_from) { 629 629 $ship_from_attr_value[$country_from] = $attr_val['id']; 630 630 } -
ali2woo-lite/trunk/includes/libs/json_api/controllers/core.php
r3250609 r3260902 15 15 protected Woocommerce $WoocommerceModel; 16 16 protected ProductService $ProductService; 17 protected Aliexpress $AliexpressModel; 18 protected PriceFormulaService $PriceFormulaService; 17 19 18 20 public function __construct( … … 20 22 ProductImport $ProductImportModel, 21 23 Woocommerce $WoocommerceModel, 22 ProductService $ProductService 24 ProductService $ProductService, 25 Aliexpress $AliexpressModel, 26 PriceFormulaService $PriceFormulaService 23 27 ) { 24 28 … … 27 31 $this->WoocommerceModel = $WoocommerceModel; 28 32 $this->ProductService = $ProductService; 33 $this->AliexpressModel = $AliexpressModel; 34 $this->PriceFormulaService = $PriceFormulaService; 29 35 30 36 //todo: perhaps it would be better to move this call to some other controller … … 101 107 } 102 108 103 $PriceFormulaService = A2WL()->getDI()->get('AliNext_Lite\PriceFormulaService');104 105 109 $imported = !!$this->WoocommerceModel->get_product_id_by_external_id($product[ImportedProductService::FIELD_EXTERNAL_PRODUCT_ID]) || !!$this->ProductImportModel->get_product($product[ImportedProductService::FIELD_EXTERNAL_PRODUCT_ID]); 106 110 // $post_id = $wpdb->get_var($wpdb->prepare("SELECT post_id FROM $wpdb->postmeta WHERE meta_key='_a2w_external_id' AND meta_value='%s' LIMIT 1", $product['id'])); … … 110 114 : array(); 111 115 112 $result = $this->ProductService->loadProductWithShippingInfo($product[ImportedProductService::FIELD_EXTERNAL_PRODUCT_ID], $params); 116 $result = $this->AliexpressModel->load_product( 117 $product[ImportedProductService::FIELD_EXTERNAL_PRODUCT_ID], $params 118 ); 119 113 120 if ($result['state'] !== 'error') { 114 121 $product = array_replace_recursive($product, $result['product']); 115 $product = $ PriceFormulaService->applyFormula($product);122 $product = $this->PriceFormulaService->applyFormula($product); 116 123 117 124 $result = $this->ProductImportModel->add_product($product); -
ali2woo-lite/trunk/readme.txt
r3254982 r3260902 309 309 310 310 == Changelog == 311 = 3.5.5 - 2025.24.03 = 312 * Improved the attribute renaming feature in the Import List. Changes are now preserved after reloading the Import List 313 * Resolved several issues with the product import functionality that arose from recent refactoring. 314 311 315 = 3.5.4 - 2025.12.03 = 312 316 * Improve code security -
ali2woo-lite/trunk/view/import.php
r3254982 r3260902 500 500 </td> 501 501 <?php foreach ($var['attributes'] as $j => $av): ?> 502 <td data-attr-id="<?php echo explode(":", $av)[0]; ?>"><input type="text" class="form-control attr" data-id="<?php echo $av; ?>" value="<?php echo isset($var['attributes_names'][$j]) ? $var['attributes_names'][$j] : ''; ?>"></td> 502 <td data-attr-id="<?php echo explode(":", $av)[0]; ?>"> 503 <input type="text" class="form-control attr" data-id="<?php echo $av; ?>" value="<?php echo $var['attributes_names'][$j] ?? ''; ?>"> 504 </td> 503 505 <?php endforeach; ?> 504 506 <td style="white-space: nowrap;" class="external-price" data-value="<?php echo $var['price']; ?>"><?php echo $localizator->getLocaleCurr($var['currency']); ?><?php echo $var['price']; ?></td> -
ali2woo-lite/trunk/view/order-fulfillment/partials/fulfillment_order_items.php
r3254982 r3260902 67 67 <td class="shipping_company"> 68 68 <select class="current-shipping-company"> 69 <?php if (!empty($item['shipping_items'])) : ?> 69 70 <?php foreach ($item['shipping_items'] as $si): ?> 70 71 <option value="<?php echo $si['serviceName'] . '" ' . ($si['serviceName'] == $item['current_shipping'] ? ' selected="selected"' : ''); ?>"> … … 72 73 </option> 73 74 <?php endforeach; ?> 75 <?php else : ?> 76 <option> 77 <?php echo esc_html__('Shipping unavailable for this address', 'ali2woo'); ?> 78 </option> 79 <?php endif; ?> 74 80 </select> 75 81 <a href="#" class="reload-companies a2wl-shipping-update-global" … … 85 91 </td> 86 92 <td class="delivery_time"> 87 <?php echo esc_html__($item['current_delivery_time'] . ' days'); ?> 93 <?php if (!empty($item['shipping_items'])) : ?> 94 <?php echo esc_html__($item['current_delivery_time'] . ' days', 'ali2woo'); ?> 95 <?php else : ?> 96 — 97 <?php endif; ?> 88 98 </td> 89 99 <td class="shipping_cost"> 90 <?php echo $item['current_shipping_cost'] ? wc_price($item['current_shipping_cost'], ['currency' => $order_data['currency']]) : esc_html__('Free Shipping', 'ali2woo'); ?> 100 <?php if (!empty($item['shipping_items'])) : ?> 101 <?php 102 echo $item['current_shipping_cost'] ? 103 wc_price($item['current_shipping_cost'], ['currency' => $order_data['currency']]) : 104 esc_html__('Free Shipping', 'ali2woo'); ?> 105 <?php else : ?> 106 — 107 <?php endif; ?> 91 108 </td> 92 109 <td class="cost"> 110 <?php if (!empty($item['shipping_items'])) : ?> 93 111 <?php echo wc_price($item['cost'], ['currency' => $order_data['currency']]) . ' x ' . esc_html__($item['quantity']); ?> = 94 112 <strong> 95 113 <?php echo wc_price($item['cost'] * $item['quantity'], ['currency' => $order_data['currency']]); ?> 96 114 </strong> 115 <?php else : ?> 116 — 117 <?php endif; ?> 97 118 </td> 98 119 <td class="total_cost"> 120 <?php if (!empty($item['shipping_items'])) : ?> 99 121 <strong> <?php echo wc_price($item['total_cost'], ['currency' => $order_data['currency']]); ?></strong> 122 <?php else : ?> 123 — 124 <?php endif; ?> 100 125 </td> 101 126 <td class="actions">
Note: See TracChangeset
for help on using the changeset viewer.