首页 > 解决方案 > WooCommerce - 为非注册用户获取发货国家

问题描述

大家早上好。如果运输目的地包含在特定的值数组中,我需要实施一种方法从总成本中减去运输成本。 这不是免费送货的情况,因为稍后会出于其他原因添加此费用。

我不能根据用户所在国家/地区做出决定,原因有两个:

  1. 用户不能注册
  2. 用户国和发货国可以不同。

我看到 WooCommerce 在我更改帐单/发货国家/地区时重新加载订单总数。我相信我需要拦截这种更改并触发插入新购物车费用的操作(当然是负费用)。

好吧,我该怎么做?

这是我的代码的一部分

function delayShippingCosts(){
  global $woocommerce;
  $EUcountries = ['IT','AT','BE','BG','CY','HR','DK','EE','FI','FR','DE','GR','IE','LV','LT','LU','MT','NE','PL','PT','CZ','RO','SK','SI','ES','SE','HU'];
  return in_array( $woocommerce->customer->get_country() , $EUcountries);
}

add_action( 'woocommerce_cart_calculate_fees', 'scc_detract_shipping_costs' );
function scc_detract_shipping_costs(){
  global $woocommerce;
  
  if(delayShippingCosts()){

    $shippingCosts = WC()->cart->get_shipping_total() * -1;
    if(current_user_can('administrator')) {
       $woocommerce->cart->add_fee( 'Delayed shipping costs', $shippingCosts, true, 'standard' );
    }
  }

}

问题是现在我正在查看我的客户数据,这些数据不是动态的(对于未注册/未登录的用户无效)。

有什么建议么?谢谢!!

编辑

几乎可以

我设法从“woocommerce_checkout_update_order_review”钩子中检索了发货国家,如下所示:

function action_woocommerce_checkout_update_order_review($posted_data) {
  global $shipTo;
 
  $data = array();
  $vars = explode('&', $posted_data);
  foreach ($vars as $k => $value){
    $v = explode('=', urldecode($value));
    $data[$v[0]] = $v[1];
  }

  WC()->cart->calculate_shipping();
  $shipTo = $data['shipping_country'] ? $data['shipping_country'] : $data['billing_country'];

 // REMOVE ALL NOTICES, IF PRESENTS...
 wc_clear_notices();

}
add_action('woocommerce_checkout_update_order_review', 'action_woocommerce_checkout_update_order_review', 10, 1);


add_action( 'woocommerce_cart_calculate_fees', 'scc_detract_shipping_costs' );
function scc_detract_shipping_costs(){
   global $woocommerce;
   ... something ...
   if(condition) {
     wc_add_notice("info message", "error");
   }
}

我的问题是,当“条件”为假时,通知不会被删除。我尝试在 woocommerce_cart_calculate_fees 和 woocommerce_checkout_update_order_review 中调用 wc_remove_notices()。差别不大!:(

有什么提示吗?

标签: wordpresswoocommerceshipping

解决方案


delayShippingCosts()不需要该功能。您可以通过类的get_european_union_countries方法获取欧洲国家的列表(除非您想自定义列表)WC_Countries

此外,您还通过课程的get_country()方法获得了国家WC_Customer

WC_Customer::get_country 函数自 3.0 版起已弃用。

你可以像这样得到国家:

  • WC()->customer->get_shipping_country()收货地址所在的国家
  • WC()->customer->get_billing_country()账单地址所在的国家

最后,请注意,要为费用应用标准税级,您必须将第 4 个参数设置为空字符串,而不是'standard'. 请参阅此处了解更多信息。


从未使用Hook登录的用户那里获取国家/地区字段woocommerce_cart_calculate_fees

当结帐中的相应字段发生变化时,您可以发送 AJAX 调用以发送帐单和发货国家/地区值。

为了确保 AJAX 函数在woocommerce_cart_calculate_fees钩子之前执行,有必要update_totals_on_change从帐单和运输国家字段中删除类(以避免进行 AJAX 调用以更新结帐)并仅在调用 AJAX 后更新结帐完全的。

此方法可能需要几毫秒/秒的额外时间来更新结帐,因为您必须等待 AJAX 调用才能完成创建选项。

有关如何在 Wordpress 中提交 AJAX 调用的更多详细信息,请参阅此答案。

在活动主题的 functions.php 中添加以下代码:

// enqueue the script for the AJAX call
add_action('wp_enqueue_scripts', 'add_js_scripts'); 
function add_js_scripts(){
   wp_enqueue_script( 'ajax-script', get_stylesheet_directory_uri().'/js/script.js', array('jquery'), '1.0', true );
   wp_localize_script( 'ajax-script', 'ajax_object', array( 'ajaxurl' =>   admin_url( 'admin-ajax.php' ) ) );
}

// update options with checkout country values
add_action( 'wp_ajax_nopriv_set_option_country', 'set_option_country' );
add_action( 'wp_ajax_set_option_country', 'set_option_country' );
function set_option_country() {

   if ( isset( $_POST ) ) {
      // get the countries valued in the checkout by the user (guest or logged in)
      $countries = $_POST['countries'];
      $billing_country = $countries['billing_country'];
      $shipping_country = $countries['shipping_country'];

      // update options
      update_option( 'guest_billing_country', $billing_country );
      update_option( 'guest_shipping_country', $shipping_country );

      // returns the output as a response to the AJAX call
      echo 'success';

   }

   // always die in functions echoing AJAX content
   die();

}

创建一个script.js文件并将其添加到目录中的子主题中(因为我使用get_stylesheet_directory_uri()而不是get_template_directory_uri()/child-theme/js/script.js::

jQuery(function($){

    // disable AJAX update
    $('#billing_country_field').removeClass('update_totals_on_change');
    $('#shipping_country_field').removeClass('update_totals_on_change');

    // when the country fields change
    $('#billing_country, #shipping_country').change(function(){
        var countries = {
            'billing_country': $('#billing_country').val(),
            'shipping_country': $('#shipping_country').val(),
        };
        $.ajax({
            url: ajax_object.ajaxurl,
            type : 'post',
            data: {
                'action': 'set_option_country',
                'countries': countries
            },
            complete: function(){
                // update checkout via AJAX
                $(document.body).trigger('update_checkout');
            },
            success:function(data) {
                console.log(data);
            },
            error: function(errorThrown){
                console.log(errorThrown);
            }
        });  
    });
});

该代码已经过测试并且可以工作。

因此,正确的scc_detract_shipping_costs功能将是:

add_action( 'woocommerce_cart_calculate_fees', 'scc_detract_shipping_costs' );
function scc_detract_shipping_costs(){

   $countries = new WC_Countries();
   // get the list of countries of the european union
   $eu_countries = $countries->get_european_union_countries();

   // get countries from checkout
   $billing_country = get_option( 'guest_billing_country' );
   $shipping_country = get_option( 'guest_shipping_country' );

   // if the shipping country is part of the European Union
   if ( in_array( $shipping_country, $eu_countries ) ) {
      $shippingCosts = WC()->cart->get_shipping_total() * -1;
      if ( current_user_can('administrator') ) {
         WC()->cart->add_fee( 'Delayed shipping costs', $shippingCosts, true, '' );
      }
   }
}

该代码已经过测试并且可以工作。将它添加到您的活动主题的functions.php。


从未使用Hook登录的用户那里获取国家/地区字段woocommerce_calculate_totals

add_action( 'woocommerce_calculate_totals', 'get_post_checkout_data' );
function get_post_checkout_data( $cart ) {

   // get post data
   if ( isset( $_POST['post_data'] ) ) {
      parse_str( $_POST['post_data'], $post_data );
   } else {
      $post_data = $_POST;
   }
   
   if ( ! empty( $post_data ) ) {
      $billing_country  = $post_data['billing_country'];
      $shipping_country = $post_data['shipping_country'];
      // ...
   }

}

在活动主题的functions.php 中添加代码。


推荐阅读