英文:
Unable to select shipping method after filtering 'woocommerce_package_rates'
问题
我刚写了这个过滤器来在有免费运输时禁用非免费运输方法:
add_filter( 'woocommerce_package_rates', 'disable_paid_shipping', 9999, 2 );
function disable_paid_shipping( $rates, $package ) {
$free_rates = array();
foreach ( $rates as $i => $rate ) {
if ( str_contains( $rate->label, "gratuita" ) OR str_contains( $rate->label, "gratuito" ) ) {
$free_rates[] = $rate;
}
if ( str_contains( $rate->id, "local") ) {
$local = $rate;
}
if ( str_contains( $rate->id, "fermopoint") ) {
$fermopoint = $rate;
}
}
if ( !empty( $free_rates ) ) {
if ( isset($fermopoint) ) {
$fermopoint->cost = 0;
$fermopoint->label .= ' gratuito';
array_unshift( $free_rates, $fermopoint );
}
if ( isset($local) ) {
$free_rates[] = $local;
}
$rates = $free_rates;
}
return $rates;
}
该代码按预期运行,但有两个意外事件:
- 不再默认选择任何运输方法(无论是购物车还是结账页面)
- 在购物车页面中选择一个运输方式后,立即取消选择
为了解决第一个问题,在结账时,可以通过woocommerce_before_cart
挂钩强制选择(尽管这看起来像是一种强制性的技巧)。
至于第二个问题,我没有想法。
有什么建议吗?
英文:
I just wrote this filter to disable non-free shipping methods when free shipping is available:
add_filter( 'woocommerce_package_rates', 'disable_paid_shipping', 9999, 2 );
function disable_paid_shipping( $rates, $package ) {
$free_rates = array();
foreach ( $rates as $i => $rate ) {
if ( str_contains( $rate->label, "gratuita" ) OR str_contains( $rate->label, "gratuito" ) ) {
$free_rates[] = $rate;
}
if ( str_contains( $rate->id, "local") ) {
$local = $rate;
}
if ( str_contains( $rate->id, "fermopoint") ) {
$fermopoint = $rate;
}
}
if ( !empty( $free_rates ) ) {
if ( isset($fermopoint) ) {
$fermopoint->cost = 0;
$fermopoint->label .= ' gratuito';
array_unshift( $free_rates, $fermopoint );
}
if ( isset($local) ) {
$free_rates[] = $local;
}
$rates = $free_rates;
}
return $rates;
}
The code works as expected, unless for two unexpected events occurring:
- no shipping method is selected by default anymore (both in cart and checkout page)
- when I choose one in the cart page, it gets unselected right after (only in cart page)
To solve the 1st problem at checkout, I can work around by forcing the selection through a hook on woocommerce_before_cart
(although this looks like a forced trick).
For the 2nd problem I have no idea.
Suggestions?
答案1
得分: 0
问题出在WC的$rates数组是一个关联数组:
$rates = Array (
[rate_id_0] => [rate_obj_0]
[rate_id_1] => [rate_obj_1]
...
);
而新创建的$free_rates是一个索引数组:
$free_rates = Array (
[0] => [rate_obj_0]
[1] => [rate_obj_1]
...
);
因此,WC无法将新的$free_rates数组与用户的默认rate_id匹配,该默认rate_id应该用作数组键。
以下是工作代码:
add_filter( 'woocommerce_package_rates', 'disable_paid_shipping', 9999, 2 );
function disable_paid_shipping( $rates, $package ) {
$free_rates = array();
foreach ( $rates as $i => $rate ) {
if ( str_contains( $rate->label, "gratuita" ) OR str_contains( $rate->label, "gratuito" ) ) {
$free_rates[$rate->id] = $rate;
}
if ( str_contains( $rate->id, "local" ) ) {
$local = $rate;
}
if ( str_contains( $rate->id, "fermopoint" ) ) {
$fermopoint = $rate;
}
}
if ( !empty( $free_rates ) ) {
if ( isset($fermopoint) ) {
$fermopoint->cost = 0;
$fermopoint->label .= ' gratuito';
$free_rates = array($fermopoint->id => $fermopoint) + $free_rates; // 将其设置为第一个
}
if ( isset($local) ) {
$free_rates[$local->id] = $local;
}
$rates = $free_rates;
}
return $rates;
}
请注意,这只是代码的翻译部分。如果您有任何其他问题或需要进一步的帮助,请随时提问。
英文:
The problem lies in that the WC $rates array is an associative array:
$rates = Array (
[rate_id_0] => [rate_obj_0]
[rate_id_1] => [rate_obj_1]
...
);
While the newly created $free_rates is an indexed array:
$free_rates = Array (
[0] => [rate_obj_0]
[1] => [rate_obj_1]
...
);
As result, WC is unable to match the new $free_rates array with the user's default rate_id, which is supposed to be used as the array key.
Here's the working code:
add_filter( 'woocommerce_package_rates', 'disable_paid_shipping', 9999, 2 );
function disable_paid_shipping( $rates, $package ) {
$free_rates = array();
foreach ( $rates as $i => $rate ) {
if ( str_contains( $rate->label, "gratuita" ) OR str_contains( $rate->label, "gratuito" ) ) {
$free_rates[$rate->id] = $rate;
}
if ( str_contains( $rate->id, "local") ) {
$local = $rate;
}
if ( str_contains( $rate->id, "fermopoint") ) {
$fermopoint = $rate;
}
}
if ( !empty( $free_rates ) ) {
if ( isset($fermopoint) ) {
$fermopoint->cost = 0;
$fermopoint->label .= ' gratuito';
$free_rates = array($fermopoint->id => $fermopoint) + $free_rates; // to set it as 1st
}
if ( isset($local) ) {
$free_rates[$local->id] = $local;
}
$rates = $free_rates;
}
return $rates;
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论