Plugin Directory

Changeset 3260902


Ignore:
Timestamp:
03/24/2025 02:50:09 PM (12 months ago)
Author:
ali2woo
Message:

new plugin release 3.5.5

Location:
ali2woo-lite/trunk
Files:
24 edited

Legend:

Unmodified
Added
Removed
  • ali2woo-lite/trunk/alinext-lite.php

    r3254982 r3260902  
    66Text Domain: ali2woo
    77Domain Path: /languages
    8 Version: 3.5.4
     8Version: 3.5.5
    99Author: Dropshipping Guru
    1010Author 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  
    943943                .find('.current-shipping-company');
    944944
    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            }
    952956
    953957            $select.html(options).trigger('change');
     
    960964
    961965            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) {
    968972                    let cost;
    969973                    let selected_item;
    970974
    971975                    $.each(items, function (i, item) {
    972                         if (item.serviceName === method) {
     976                        if (item.serviceName === method || !method) {
    973977                            cost = item.previewFreightAmount ?
    974978                                item.previewFreightAmount.value :
    975979                                item.freightAmount.value
    976980                            selected_item = item;
     981                            return;
    977982                        }
    978983                    });
     
    21182123
    21192124        function prepareProductUpdateData(product, updateDescription = false) {
    2120             var updateData = {
     2125            const updateData = {
    21212126                title: $(product).find('input.title').val(),
    21222127                sku: $(product).find('input.sku').val(),
     
    21612166
    21622167        $('.a2wl-content .product input.attr-name').change(function () {
    2163             var product = $(this).parents('.product');
     2168            let product = $(this).parents('.product');
    21642169            a2wl_update_product($(product).attr('data-id'), prepareProductUpdateData(product));
    21652170        });
     
    21702175        });
    21712176
    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');
    21742212            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);
    21912214        });
    21922215
     
    21952218        });
    21962219
    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
    21982223            if ($(this).hasClass('set-new-value')) {
    21992224                $(this).parents('.price-edit-selector').find('.price-box-top input[type="text"]').attr('placeholder', 'Enter Value');
     
    22172242                const attr_id = $(this).parents('td').attr('data-attr-id');
    22182243
    2219                 $(".a2wl-rename-attrs-modal")
     2244                const $modal = $(".a2wl-rename-attrs-modal");
     2245                $modal
    22202246                    .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                    });
    22232251
    22242252                $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                );
    22332271
    22342272                $('.price-edit-selector').find('.price-box-top').hide();
    2235 
    2236                 return;
    22372273            }
    22382274
     
    22632299            $attrInputs.each(function () {
    22642300                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();
    22682302            });
    22692303
     
    23112345            });
    23122346
    2313 
    23142347            //save
    23152348            if (!duplicatesKeys.length) {
     
    23202353                $('.a2wl-rename-attrs-modal').removeClass('opened');
    23212354            }
     2355
     2356            importListAPI.updateProductAttributes($product);
    23222357        });
    23232358
  • ali2woo-lite/trunk/changelog.txt

    r3254982 r3260902  
    349349* Fix bug with non-Latin characters in the attribute name feature of the import list
    350350
     3513.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  
    281281            get(ProductService::class),
    282282            get(WoocommerceService::class),
     283            get(Review::class),
     284            get(Woocommerce::class),
     285            get(PriceFormulaService::class),
    283286        ),
    284287    'AliNext_Lite\SearchPageController' => create(SearchPageController::class)
     
    316319            get(Woocommerce::class),
    317320            get(ProductService::class),
     321            get(Aliexpress::class),
     322            get(PriceFormulaService::class)
    318323        ),
    319324];
  • ali2woo-lite/trunk/includes/classes/connector/AliexpressDefaultConnector.php

    r3250609 r3260902  
    141141            'quantity' => $quantity,
    142142            'country_code' => $country_code,
     143            'country_code_from' => $country_code_from,
    143144            'extra_data' => $extra_data,
    144145        ];
  • ali2woo-lite/trunk/includes/classes/controller/FrontendInitController.php

    r3254982 r3260902  
    159159        }
    160160
    161         $countryFromCode = 'CN';
    162 
    163161        try {
     162            $countryFromCode = $this->WoocommerceService->getShippingFromByProduct($WC_ProductOrVariation);
    164163            $importedProduct = $this->WoocommerceService->updateProductShippingItems(
    165164                $WC_ProductOrVariation,
  • ali2woo-lite/trunk/includes/classes/controller/ImportAjaxController.php

    r3254982 r3260902  
    929929            if (get_setting('allow_product_duplication') || !$post_id) {
    930930                $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);
    932932                if ($res['state'] !== 'error') {
    933933                    $product = array_replace_recursive($product, $res['product']);
     
    10821082        //todo: Here we take product countries to pass as parameters
    10831083        //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]) ?
    10851085            $importedProduct[ImportedProductService::FIELD_COUNTRY_FROM] :
    1086             'CN';
     1086            'CN';*/
    10871087
    10881088        $product_country_to = !empty($importedProduct[ImportedProductService::FIELD_COUNTRY_TO])
     
    10911091
    10921092        $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);
    10941095
    10951096        //todo: $externalSkuId should be update if the product variations are changed
     
    12111212
    12121213        $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);
    12141217
    12151218        try {
    12161219            $importedProduct = $this->WoocommerceService->updateProductShippingInfo(
    1217                 $WC_ProductOrVariation,
    1218                 $countryToCode,
    1219                 $countryFromCode
     1220                $WC_ProductOrVariation, $countryToCode,
    12201221            );
    12211222
     
    12881289
    12891290        $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        );
    12911294
    12921295        $countryCode = ProductShippingData::meta_key($countryFromCode, $countryToCode);
     
    14431446        }
    14441447
    1445        // a2wl_error_log('Aliexpress categories from server: ' . print_r($productCategoryInfo, true));
    1446 
    14471448        $insertedCategories = [];
    14481449
  • ali2woo-lite/trunk/includes/classes/controller/OrderFulfillmentController.php

    r3254982 r3260902  
    517517                    <?php endif; ?>
    518518                    */ ?>
    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>
    520520                </div>
    521521            </div>
     
    537537    }
    538538
     539    /**
     540     * On order fulfillment popup loading
     541     * @return void
     542     */
    539543    public function ajax_load_fulfillment_orders_html(): void
    540544    {
     
    580584            $this->model_put("ProductShippingDataService", $this->ProductShippingDataService);
    581585            $this->model_put("ImportedProductServiceFactory", $this->ImportedProductServiceFactory);
    582 
    583             //$ProductShippingDataService
    584586
    585587            foreach ($orders_data as $order_data) {
  • ali2woo-lite/trunk/includes/classes/controller/WooCommerceProductListController.php

    r3254982 r3260902  
    1818    protected ProductService $ProductService;
    1919    protected WoocommerceService $WoocommerceService;
     20    protected Review $ReviewModel;
     21    protected Woocommerce $WoocommerceModel;
     22    protected PriceFormulaService $PriceFormulaService;
    2023
    2124    private $bulk_actions = [];
     
    2427    public function __construct(
    2528        ProductService $ProductService,
    26         WoocommerceService $WoocommerceService
     29        WoocommerceService $WoocommerceService,
     30        Review $ReviewModel,
     31        Woocommerce $WoocommerceModel,
     32        PriceFormulaService $PriceFormulaService
    2733    ) {
    2834        parent::__construct();
     
    3036        $this->ProductService = $ProductService;
    3137        $this->WoocommerceService = $WoocommerceService;
     38        $this->ReviewModel = $ReviewModel;
     39        $this->WoocommerceModel = $WoocommerceModel;
     40        $this->PriceFormulaService = $PriceFormulaService;
    3241
    3342        add_action('admin_footer-edit.php', array($this, 'scripts'));
     
    271280        a2wl_init_error_handler();
    272281        try {
    273             /** @var $woocommerce_model Woocommerce */
    274             $woocommerce_model = A2WL()->getDI()->get('AliNext_Lite\Woocommerce');
    275             $PriceFormulaService = A2WL()->getDI()->get('AliNext_Lite\PriceFormulaService');
    276 
    277282            $ids = isset($_POST['ids']) ? (is_array($_POST['ids']) ? $_POST['ids'] : array($_POST['ids'])) : array();
    278283
     
    319324                    foreach ($res['products'] as $product) {
    320325                        $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));
    323328                    }
    324329
     
    347352        a2wl_init_error_handler();
    348353        try {
    349             /** @var $woocommerce_model  Woocommerce */
    350             $woocommerce_model = A2WL()->getDI()->get('AliNext_Lite\Woocommerce');
    351 
    352354            $ids = isset($_POST['ids']) ? (is_array($_POST['ids']) ? $_POST['ids'] : array($_POST['ids'])) : array();
    353355
    354356            $error = 0;
    355357            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);
    357359                if ($external_id) {
    358360                    try {
    359                         $reviews_model = new Review();
    360                         $reviews_model->load($post_id, true);
     361                        $this->ReviewModel->load($post_id, true);
    361362                    } catch (Throwable $e) {
    362                         a2wl_print_throwable($e);
    363                         $error++;
    364                     } catch (\Exception $e) {
    365363                        a2wl_print_throwable($e);
    366364                        $error++;
     
    371369            }
    372370
    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            ];
    374378        } catch (Throwable $e) {
    375379            a2wl_print_throwable($e);
     
    393397
    394398        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']);
    398400            if ($id) {
    399401                $result = ResultBuilder::buildOk(array('id' => $id));
  • ali2woo-lite/trunk/includes/classes/dto/ShippingItemDto.php

    r3250609 r3260902  
    1212{
    1313    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,
    1519    ) {}
    1620
     
    2428        return $this->cost;
    2529    }
     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    }
    2645}
  • ali2woo-lite/trunk/includes/classes/factory/ExternalOrderFactory.php

    r3250609 r3260902  
    203203            $productType = $orderItem->get_product()->get_type();
    204204
    205             if ($productType == 'variation') {
     205            if ($productType === 'variation') {
    206206                $variationId = $orderItem->get_variation_id();
    207207                $WC_Product_Variation = new WC_Product_Variation($variationId);
  • ali2woo-lite/trunk/includes/classes/model/Aliexpress.php

    r3254982 r3260902  
    99namespace AliNext_Lite;;
    1010
     11use DOMDocument;
    1112use Throwable;
    1213
     
    461462        );
    462463
    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 
    469464        if (!empty($result['state']) && $result['state'] !== 'error') {
    470465            return $result['items'];
     
    489484
    490485        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');
    492487        } 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            );
    494491        }
    495492
     
    499496
    500497        if ($html && class_exists('\DOMDocument')) {
    501             $dom = new \DOMDocument();
     498            $dom = new DOMDocument();
    502499            @$dom->loadHTML($html);
    503500            $dom->formatOutput = true;
     
    818815    private function normalizeLoadedShippingInfo(array $product): array
    819816    {
    820         $hasShippingInfo = isset($product['shipping_info']['items']) &&
     817        $hasShippingInfo = !empty($product['shipping_info']['items']) &&
    821818            is_array($product['shipping_info']['items']);
    822819
  • ali2woo-lite/trunk/includes/classes/model/Woocommerce.php

    r3254982 r3260902  
    253253                    ],
    254254                    '_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,
    258261                    '_a2w_orders_count' => (!empty($product['ordersCount']) ? intval($product['ordersCount']) : 0),
    259262                    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,
    261266                ],
    262267            ];
     
    382387
    383388            // 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                );
    386395            } 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                );
    388399            }
    389400
     
    396407            if (get_option('woocommerce_manage_stock', 'no') === 'yes') {
    397408                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                );
    399412                update_post_meta($product_id, '_stock', $total_quantity);
    400413            } else {
     
    404417            }
    405418
    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)
    409420                && (!$override_product || $override_title_description)
    410421            ) {
     
    795806
    796807        // 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            );
    799813        } 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']);
    801815        }
    802816
     
    960974
    961975        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');
    963977        } 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            );
    965981        }
    966982
     
    11801196    }
    11811197
    1182     private function set_attributes($product_id, $attributes)
     1198    private function set_attributes(int $product_id, array $attributes): void
    11831199    {
    11841200        if (defined('A2WL_IMPORT_EXTENDED_ATTRIBUTE')) {
     
    11931209            $this->helper->set_woocommerce_attributes($product_id, $attributes);
    11941210        } else {
    1195             $tmp_product_attr = array();
     1211            $tmp_product_attr = [];
    11961212            foreach ($attributes as $attr) {
    11971213                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']];
    11991215                } 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 = [];
    12051224            foreach ($tmp_product_attr as $name => $value) {
    1206                 $product_attributes[str_replace(' ', '-', $name)] = array(
     1225                $product_attributes[str_replace(' ', '-', $name)] = [
    12071226                    'name' => $name,
    12081227                    'value' => implode(', ', $value),
     
    12111230                    'is_variation' => 0,
    12121231                    'is_taxonomy' => 0,
    1213                 );
     1232                ];
    12141233            }
    12151234
     
    19211940                    }
    19221941
    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                        );
    19251948                    } 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                        );
    19271952                    }
    19281953
  • ali2woo-lite/trunk/includes/classes/service/ImportedProductService.php

    r3254982 r3260902  
    3333    public const FIELD_EXTERNAL_SKU_ID = 'skuId';
    3434    public const FIELD_EXTERNAL_PRODUCT_ID = 'id';
     35    public const FIELD_COUNTRY_CODE = 'country_code';
    3536
    3637    private array $shouldShowVideoTabStates = [
  • ali2woo-lite/trunk/includes/classes/service/OrderFulfillmentService.php

    r3254982 r3260902  
    281281                $quantity = $item->get_quantity();
    282282
    283                 $countryFromCode = 'CN';
     283                $countryFromCode = $this->WoocommerceService->getShippingFromByProduct($WC_Product);
    284284
    285285                $importedProduct = $this->WoocommerceService
     
    297297                $current_delivery_time = '-';
    298298                $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());
    300307
    301308                if ($shipping_meta_data) {
     
    305312                    $current_shipping_cost = $shipping_meta_data['shipping_cost'];
    306313                }
    307                 $current_shipping_company = $current_shipping_company ?: $ShippingItemDto->getMethodName();
     314                $current_shipping_company = $current_shipping_company ?: $ShippingItemDto->getMethodName();*/
    308315
    309316                $wpml_product_id = $wpml_variation_id = '';
  • ali2woo-lite/trunk/includes/classes/service/ProductService.php

    r3254982 r3260902  
    180180        if (isset($product['sku_products'])) {
    181181            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];
    184185                }
    185186               /* if ($var['id'] === $variationExternalId) {
     
    230231
    231232        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';
    232253    }
    233254
     
    294315        }
    295316
     317        /**
     318         * todo: need to use hasTracking and companyName too in code which calls findDefaultFromShippingItems
     319         */
    296320        $shipping_cost = 0;
     321        $shippingTime = '';
     322        $hasTracking = false;
     323        $companyName = '';
    297324        foreach ($shippingItems as $shippingItem) {
    298325            if ($shippingItem['serviceName'] == $default_method) {
     326                $shippingTime = $shippingItem['time'] ?? '';
     327                $hasTracking = isset($shippingItem['tracking']) && $shippingItem['tracking'];
     328                $companyName =  $shippingItem['company'] ?? $shippingItem['serviceName'];
    299329                $shipping_cost = $shippingItem['previewFreightAmount']['value'] ?? $shippingItem['freightAmount']['value'];
    300330                $shipping_cost = apply_filters('wcml_raw_price_amount', $shipping_cost, $current_currency);
     
    302332        }
    303333
    304         return new ShippingItemDto($default_method, $shipping_cost);
     334        return new ShippingItemDto(
     335            $default_method, $shipping_cost, $companyName, $shippingTime, $hasTracking
     336        );
    305337    }
    306338
  • ali2woo-lite/trunk/includes/classes/service/ProductShippingDataService.php

    r3254982 r3260902  
    1111class ProductShippingDataService
    1212{
    13 
    14     public const META_COUNTRY_CODE = '_a2w_country_code';
    1513
    1614    protected ProductShippingDataRepository $ProductShippingDataRepository;
     
    8280            "ON (pm.post_id=p.ID AND pm.meta_key=%s) WHERE p.post_parent=%d AND p.post_type=%s";
    8381
    84         $query = $wpdb->prepare($query,self::META_COUNTRY_CODE, $productId, 'product_variation');
     82        $query = $wpdb->prepare($query,ImportedProductService::KEY_COUNTRY_CODE, $productId, 'product_variation');
    8583        $countryFromList = $wpdb->get_col($query);
    8684
     
    8886            $query = "SELECT DISTINCT pm.meta_value FROM {$wpdb->postmeta} pm WHERE pm.post_id=%d AND pm.meta_key=%s";
    8987
    90             $query = $wpdb->prepare($query, $productId, self::META_COUNTRY_CODE);
     88            $query = $wpdb->prepare($query, $productId, ImportedProductService::KEY_COUNTRY_CODE);
    9189            $countryFromList = $wpdb->get_col($query);
    9290        }
  • ali2woo-lite/trunk/includes/classes/service/WoocommerceService.php

    r3254982 r3260902  
    4040     */
    4141    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,
    4443    ): array {
    4544        $ImportedProductService = $this->ImportedProductServiceFactory
     
    5453            return $this->ProductService->updateProductShippingInfo(
    5554                $importedProduct,
    56                 $countryFromCode,
     55                $ImportedProductService->getShippingFromCountryCode(),
    5756                $countryToCode,
    5857                $ImportedProductService->getExternalSkuId(),
     
    6867     */
    6968    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,
    7270    ): array {
    7371        $importedProduct = $this->getProductShippingInfo(
    74             $WC_ProductOrVariation, $countryToCode, $countryFromCode, $quantity
     72            $WC_ProductOrVariation, $countryToCode, $quantity
    7573        );
    7674
     
    8684    }
    8785
     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
    8894    /**
    8995     * @throws RepositoryException|ServiceException
     
    94100    ): array {
    95101        $importedProduct = $this->getProductShippingInfo(
    96             $WC_ProductOrVariation, $countryToCode, $countryFromCode, $quantity
     102            $WC_ProductOrVariation, $countryToCode, $quantity
    97103        );
    98104
  • ali2woo-lite/trunk/includes/classes/utils/Helper.php

    r3250609 r3260902  
    137137        }
    138138
     139        $taxonomy = $this->cleanTaxonomyName($key);
     140
    139141        // get attribute name, label
    140142        $attribute_label = $key;
    141143
    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);
    143146
    144147        // set attribute type
     
    170173
    171174        // add attribute values if not exist
    172         $taxonomy = $this->cleanTaxonomyName($attribute_name);
    173175
    174176        $values = is_array($value) ? $value : [$value];
     
    198200                        // add term taxonomy
    199201                        $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                        );
    201210                        $term_taxonomy_id = $wpdb->insert_id;
    202211                    }
     
    233242                        // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
    234243                        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                            );
    236248                        }
    237249                    }
     
    491503    }
    492504
    493     public function load_terms($taxonomy) {
    494         global $wpdb;
     505    public function load_terms(string $taxonomy) {
     506        global $wpdb;
     507
    495508        $query = "SELECT DISTINCT t.name, t.slug FROM {$wpdb->terms} AS t " .
    496509                 "INNER JOIN {$wpdb->term_taxonomy} as tt ON tt.term_id = t.term_id " .
    497510                 "WHERE tt.taxonomy = %s";
    498511
    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
    507519        if ($wp_way && !$ignore) {
    508520            $wpdb->insert($table, $fields['values'], $fields['format']);
    509521        } 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
    524535        return $wpdb->insert_id;
    525536    }
    526537
    527     public function prepareForInList($v) {
     538    public function prepareForInList($v): string
     539    {
    528540        return "'" . $v . "'";
    529541    }
    530542
    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    {
    534545        // Sanitize taxonomy names. Slug format (no spaces, lowercase) - uses sanitize_title
    535546        if ($withPrefix) {
     
    539550        }
    540551
    541         if($checkSize){
     552        if ($checkSize) {
    542553            // limit to 32 characters (database/ table wp_term_taxonomy/ field taxonomy/ is limited to varchar(32) )
    543554            if (seems_utf8($ret)) {
     
    545556                if (function_exists('mb_substr')) {
    546557                    $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 {
    549565                $limit_max = $withPrefix ? 32 : 29; // 29 = 32 - strlen('pa_')
    550566                $ret = substr($ret, 0, $limit_max);
  • ali2woo-lite/trunk/includes/classes/utils/Utils.php

    r3250609 r3260902  
    622622        foreach ($product['sku_products']['attributes'] as $attr) {
    623623            foreach ($attr['value'] as $attr_val) {
    624                 if (isset($attr_val['country_code'])) {
     624                if (isset($attr_val[ImportedProductService::FIELD_COUNTRY_CODE])) {
    625625                    $ship_from_attr_name = $attr['name'];
    626                     if ($attr_val['country_code'] === $default_country) {
     626                    if ($attr_val[ImportedProductService::FIELD_COUNTRY_CODE] === $default_country) {
    627627                        $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) {
    629629                        $ship_from_attr_value[$country_from] = $attr_val['id'];
    630630                    }
  • ali2woo-lite/trunk/includes/libs/json_api/controllers/core.php

    r3250609 r3260902  
    1515    protected Woocommerce $WoocommerceModel;
    1616    protected ProductService $ProductService;
     17    protected Aliexpress $AliexpressModel;
     18    protected PriceFormulaService $PriceFormulaService;
    1719
    1820    public function __construct(
     
    2022        ProductImport $ProductImportModel,
    2123        Woocommerce $WoocommerceModel,
    22         ProductService $ProductService
     24        ProductService $ProductService,
     25        Aliexpress $AliexpressModel,
     26        PriceFormulaService $PriceFormulaService
    2327    ) {
    2428
     
    2731        $this->WoocommerceModel = $WoocommerceModel;
    2832        $this->ProductService = $ProductService;
     33        $this->AliexpressModel = $AliexpressModel;
     34        $this->PriceFormulaService = $PriceFormulaService;
    2935
    3036        //todo: perhaps it would be better to move this call to some other controller
     
    101107            }
    102108
    103             $PriceFormulaService = A2WL()->getDI()->get('AliNext_Lite\PriceFormulaService');
    104 
    105109            $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]);
    106110            // $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']));
     
    110114                : array();
    111115
    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
    113120                if ($result['state'] !== 'error') {
    114121                    $product = array_replace_recursive($product, $result['product']);
    115                     $product = $PriceFormulaService->applyFormula($product);
     122                    $product = $this->PriceFormulaService->applyFormula($product);
    116123
    117124                    $result = $this->ProductImportModel->add_product($product);
  • ali2woo-lite/trunk/readme.txt

    r3254982 r3260902  
    309309
    310310== 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
    311315= 3.5.4 - 2025.12.03 =
    312316* Improve code security
  • ali2woo-lite/trunk/view/import.php

    r3254982 r3260902  
    500500                                                        </td>
    501501                                                        <?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>
    503505                                                        <?php endforeach; ?>
    504506                                                        <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  
    6767            <td class="shipping_company">
    6868                <select class="current-shipping-company">
     69                    <?php if (!empty($item['shipping_items'])) : ?>
    6970                    <?php foreach ($item['shipping_items'] as $si): ?>
    7071                        <option value="<?php echo $si['serviceName'] . '" ' . ($si['serviceName'] == $item['current_shipping'] ? ' selected="selected"' : ''); ?>">
     
    7273                        </option>
    7374                    <?php endforeach; ?>
     75                    <?php else : ?>
     76                        <option>
     77                        <?php echo esc_html__('Shipping unavailable for this address', 'ali2woo'); ?>
     78                        </option>
     79                    <?php endif; ?>
    7480                </select>
    7581                <a href="#" class="reload-companies a2wl-shipping-update-global"
     
    8591            </td>
    8692            <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; ?>
    8898            </td>
    8999            <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; ?>
    91108            </td>
    92109            <td class="cost">
     110                <?php if (!empty($item['shipping_items'])) : ?>
    93111                <?php echo wc_price($item['cost'], ['currency' => $order_data['currency']]) . ' x ' . esc_html__($item['quantity']); ?> =
    94112                <strong>
    95113                    <?php echo wc_price($item['cost'] * $item['quantity'], ['currency' => $order_data['currency']]); ?>
    96114                </strong>
     115                <?php else : ?>
     116                    —
     117                <?php endif; ?>
    97118            </td>
    98119            <td class="total_cost">
     120                <?php if (!empty($item['shipping_items'])) : ?>
    99121                <strong> <?php echo wc_price($item['total_cost'], ['currency' => $order_data['currency']]); ?></strong>
     122                <?php else : ?>
     123                    —
     124                <?php endif; ?>
    100125            </td>
    101126            <td class="actions">
Note: See TracChangeset for help on using the changeset viewer.