我使用WooCommerce Per Product Shipping插件根据产品设置运费,然而,这个插件没有提供任何内置功能,只收取整个订单最昂贵的运费,就像核心的WooCommerce统一运费允许您设置计算类型一样.

我只收取最高运费的运费.我承认我使用人工智能生成了这段代码(因为我不是开发人员),我try 了几种方法来实现它,但我一直收到一个严重错误:

/**
 * Retrieve shipping costs for a WooCommerce product.
 *
 * @param int $product_id The ID of the WooCommerce product.
 * @return float|null Shipping cost for the product, or null if not found.
 */
function get_shipping_cost_for_product( $product_id ) {
    $shipping_methods = WC()->shipping->get_packages();
    
    foreach ( $shipping_methods as $package ) {
        foreach ( $package['rates'] as $rate ) {
            // Check if the shipping rate is applicable to the product.
            if ( $rate->method_id === '11' && $rate->get_instance_id() === 0 ) {
                // Retrieve the shipping cost for the product.
                return $rate->cost;
            }
        }
    }
    
    return null; // Shipping cost not found.
}

/**
 * Custom function to calculate shipping costs for WooCommerce Per Product Shipping.
 *
 * @param array $package Shipping package.
 * @return void
 */
function custom_per_product_shipping_cost( $package ) {
    if ( ! is_array( $package['contents'] ) ) {
        return;
    }

    // Initialize variables to keep track of the highest shipping cost.
    $highest_shipping_cost = 0;
    
    // Loop through each item in the cart.
    foreach ( $package['contents'] as $item_id => $item ) {
        $product_id = $item['product_id'];
        
        // Get the shipping cost for the current product.
        $shipping_cost = get_shipping_cost_for_product( $product_id );
        
        // Compare with the highest shipping cost found so far.
        if ( $shipping_cost > $highest_shipping_cost ) {
            $highest_shipping_cost = $shipping_cost;
        }
    }
    
    // Set the calculated highest shipping cost for the entire order.
    $package['contents_cost'] = $highest_shipping_cost;
    
    // Update the package shipping costs.
    WC()->cart->shipping_total      = $highest_shipping_cost;
    WC()->cart->shipping_tax_total  = 0; // You may need to adjust tax calculation.
    WC()->cart->shipping_taxes      = array();
    WC()->cart->shipping_methods    = array();
    
    // Recalculate cart totals.
    WC()->cart->calculate_totals();
}

// Hook into the shipping calculation process.
add_action( 'woocommerce_cart_shipping_packages', 'custom_per_product_shipping_cost' );

任何帮助都将不胜感激.

Per Product Shipping settings. Tax status: taxable; nothing set for Default Product Cost, Handling Fee per product or per order, and nothing checked with regard to ignoring other methods. See screenshot. plugin settings

未启用其他发货方式

On a product, I have enabled per product shipping and have added three rows (Us, HI, AK) with an item cost. See screenshot product settings

推荐答案

在您的产品设置中,该插件要求您进行一些更改:

  • 首先是带有国家/地区邮政编码的行(你没有)
  • 然后在具有为国家定义的州的行之后
  • 然后是单独的国家(所有其他州)
  • 在末尾没有指定所有其他国家/地区的行(optional)

第一个空栏(带有3条小水平线的图标)将允许您根据需要对行进行重新排序.一旦完成,就保存.

enter image description here

请注意,您的运输成本是按项目设置的,该成本将乘以该项目的购物车数量.

因此,如果我采用最昂贵的运输项目成本,它将是您设置的项目成本,乘以您 case 中的数量.如果您希望数量不增加成本,则必须更改您的产品设置.

以下代码处理按项目(受数量影响)的成本和按行项目的成本.

下面是根据客户位置获取产品运费的函数:

function get_per_product_shipping_data( $product_id, $country = '', $state = '', $postcode = '' ) {
    global $wpdb;

    $results = $wpdb->get_results( "
    SELECT *
    FROM {$wpdb->prefix}woocommerce_per_product_shipping_rules
    WHERE product_id = {$product_id}
    ORDER BY rule_order ASC;" );

    $country_found = $state_found = $postcode_found = array();

    foreach ( $results as $key => $result ) {
        if( $country === $result->rule_country ) {
            $country_found[$key] = $result;
        }
        if( $state === $result->rule_state ) {
            $state_found[$key] = $result;
        }
        if( $postcode === $result->rule_postcode ) {
            $postcode_found[$key] = $result;
        }
    }
    if( count($postcode_found) === 1 ) {
        return reset($postcode_found);
    } elseif( count($state_found) > 0 ) {
        if ( count($state_found) === 1 )
            return reset($state_found);
        elseif ( count($state_found) > 1 ) {
            return end($state_found);
        }
    }  elseif( count($country_found) > 0 ) {
        if ( count($country_found) === 1 )
            return reset($country_found);
        elseif ( count($country_found) > 1 ) {
            return end($country_found);
        }
    } elseif( count($results) === 1 ) {
        return reset($results);
    } else {
        return array();
    }
}

现在,我们可以获得最昂贵的运输成本,并使用以下设置:

add_filter( 'woocommerce_package_rates', 'custom_per_product_shipping_filtering', 10, 2 );
function custom_per_product_shipping_filtering( $rates, $package ) {
    if ( count($package['contents']) <= 1 ) return $rates;

    $country  = $package['destination']['country'];
    $state    = $package['destination']['state'];
    $postcode = $package['destination']['postcode'];

    $method_key_id  = 'per_product'; // shipping method slug
    $item_quantity_cost = $line_item_cost = $new_cost = array();
    
    // loop through cart items in the current shipping package
    foreach( $package['contents'] as $item_key => $item ){
        $shipping = get_per_product_shipping_data($item['product_id'], $country, $state, $postcode );
        if ( ! empty($shipping) ) {
            if ( $shipping->rule_item_cost > 0 ) {
                $item_quantity_cost[$item_key] = $shipping->rule_item_cost * $item['quantity'];
            }
            if ( $shipping->rule_cost > 0 ) {
                $line_item_cost[$item_key] = $shipping->rule_cost;
            }
        }
    }

    
    if( count($item_quantity_cost) > 1 ) {
        arsort($item_quantity_cost); // Sorting cost in DESC order
        $new_cost[] = reset($item_quantity_cost); // Set the more expensive cost
    }
    if( count($line_item_cost) > 1 ) {
        arsort($line_item_cost); // Sorting cost in DESC order
        $new_cost[] = reset($line_item_cost); // Set the more expensive cost
    }

    // If we find the shipping per product
    if( isset($rates[$method_key_id]) && count($new_cost) > 0 ){
        if( count($new_cost) > 0 ) {
            arsort($new_cost); // Sorting cost in DESC order
        }
        $new_cost   = reset($new_cost); // Get the most expensive individual cost
        $rate       = $rates[$method_key_id];
        $conversion =  $new_cost / $rate->cost;

        // Set the new cost
        $rates[$method_key_id]->cost = $new_cost;

        // Shipping taxes 
        $has_taxes = false; // Initializing
        $taxes     = array(); // Initializing

        // Loop through taxes array (change taxes rate cost if enabled)
        foreach ($rate->taxes as $key => $tax){
            if( $tax > 0 ){
                $taxes[$key] = $tax * $conversion; // Set the new tax cost in the array
                $has_taxes   = true; // Enabling tax changes
            }
        }
        // set the new array of shipping tax cost
        if( $has_taxes ) {
            $rates[$method_key_id]->taxes = $taxes;
        }
    }
    return $rates;
}

代码位于您的子主题的unctions.php文件中(或在插件中).经过测试和工作.

要刷新运输缓存数据(在添加代码之后),请清空购物车.

Php相关问答推荐

为什么这个方法调用用引号和花括号包裹?

如何发送woocommerce订单跟踪码与短信

在ShipStation for WooCommerce中使用自定义订单项目元数据

Symfony装置加载:try 从命名空间加载类";ClassUtils";Doctrine\Common\Util";

WooCommerce数量减号和加号图标未显示

根据未用于变体的产品属性隐藏WooCommerce发货方式

允许在WooCommerce管理员优惠券列表中显示自定义优惠券类型

我的邮箱中的链接在我的URL中添加了一个

如何在Laravel Model中自定义多个日期属性的日期格式?

即使在WooCommerce购物车中添加了两次产品,也要将所有项目设置为空白行

Regex|PHP捕获json字符串中的每个非法双引号

显示自定义 Laravel 9 公共属性的错误

无法在 WordPress 上获取 JSON 数据

用自定义代码替换 WooCommerce 单一产品简短描述

PHP API - 本地主机中的 SSL 证书问题

Google Drive API:为什么使用服务帐户在下载文件时会将我带到 Google Drive 登录窗口?

无法在 Laravel 中实例化抽象类 ProductAbstract

在 groupBy laravel 5.7 中 Select 多列

在 Symfony 测试中何时使用 TestCase 而不是 KernelTestCase

如果 static:: 被解析为B,为什么 PHP 会执行A的方法