Wordpress 添加自定义配送方式 可以添加国内的物流--已完结

488 阅读3分钟

背景:使用Wordpress 做跨境电商,想要接入国内的物流公司API。实现实时计算物流价格。
如下图:

image.png

image.png

注意 get_shipping_rate_from_api 方法中的 // $this->save_local_post_json($response); //保存返回数据 我隐藏了,我调用的是锦联物流,这里只是举例,根据自己业务来更改。

其中 cost 就是物流的价格,通过物流api计算后的价格替换 cost 参数。

return array(
	'id' => 'custom_shipping_rate',
	'label' => 'Custom Shipping Rate',
	'cost' => 50.00, // 示例费用
);

其中 save_local_post_json 方法用于查看联调数据,文件保存同目录下的post.json文件

把代码放入function.php 文件中
话不多说直接上代码都写备注了:

这家对接的物流公司只支持单个商品运费试算,多个的话我的计算方式是: 单个产品运费 * 产品数量

/**
 * 自定义物流方式
 * 首先在类的构造函数里定义运费的名称、描述、唯一ID等基本属性。
 * 在init()函数里定义运费的选项,这些选项的值会被保存到wp_options表里,再获取用户填写的值。
 * 在calculate_shipping()函数里实现运费计算的逻辑。
 * sanitize_cost()是价格字段的过滤函数,可有可无。
 */
add_action('woocommerce_shipping_init', 'define_your_shipping_method');
add_filter('woocommerce_shipping_methods', 'add_your_shipping_method');

function define_your_shipping_method()
{
	//定义运费名称、费用、计算运费方法等等的代码
	class Your_Shipping_Method extends WC_Shipping_Method
	{
		/**
		 * Constructor.
		 *
		 * @param int $instance_id Shipping method instance.
		 */
		public function __construct($instance_id = 0)
		{
			$this->id = 'your_shipping_method';
			$this->instance_id = absint($instance_id);
			$this->method_title = 'Jinlian Logistics';
			$this->method_description = '锦联物流描述信息,前台不可见';

			// 让运费支持shipping zones,而不是单独显示出来
			$this->supports = array(
				'shipping-zones',
				'instance-settings',
				'instance-settings-modal',
			);

			$this->init();

			add_action('woocommerce_update_options_shipping_' . $this->id, array($this, 'process_admin_options'));

		}

		/**
		 * Init user set variables.
		 */
		public function init()
		{

			// 定义选项字段
			$this->instance_form_fields = array(
				'title' => array(
					'title' => __('Title', 'woocommerce'),
					'type' => 'text',
					'description' => __('This controls the title which the user sees during checkout.', 'woocommerce'),
					'default' => $this->method_title,
					'desc_tip' => true,
				),
				'cost' => array(
					'title' => __('Cost', 'woocommerce'),
					'type' => 'text',
					'description' => '请输入价格',
					'default' => '0',
					'desc_tip' => true,
					'sanitize_callback' => array($this, 'sanitize_cost'),
				),
			);

			// 获取用户的选择
			$this->title = $this->get_option('title');
			$this->cost = $this->get_option('cost');
		}


		/**
		 * Calculate the shipping costs.
		 *
		 * @param array $package Package of items from cart.
		 */
		//运费计算逻辑
		public function calculate_shipping($package = array())
		{	
			
			// 调用第三方物流API接口,获取运输费用信息
			$api_rate = $this->get_shipping_rate_from_api($package);
			if ($api_rate !== false && isset($api_rate['cost']) && $api_rate['cost'] > 0) {
				$rate = array(
					'id' => $this->get_rate_id(),
					'label' => $this->get_option('title'),
					'cost' => $api_rate['cost'],
					'package' => $package,
				);
				$this->add_rate($rate);
			}
			// $rate = array(
			// 	'id' => $this->get_rate_id(),
			// 	'label' => $this->get_option('title'), //标签
			// 	'cost' => $this->get_option('cost'), //成本
			// 	'package' => $package, //包裹信息
			// ); 

			// if ($rate['cost'] > 0) {
			// 	$this->add_rate($rate);
			// }

			do_action('woocommerce_' . $this->id . '_shipping_add_rate', $this, $rate);

		}
		//调用三方物流接口
		public function get_shipping_rate_from_api($package) {
			// 使用第三方物流API发送请求并获取运输费用信息
			// 这里是示例代码,您需要替换成实际的API请求代码
			// 返回的数组应该包含'id'、'label'和'cost'等字段,与原始代码中的$rate数组格式相同
			// 如果无法成功获取运输费用信息,返回false或空数组
			// 设置请求参数  
			$product = null; //产品
			$product_num = 1; //产品数量
			$length = $width = $height = $weight = '';
			if(isset($package['contents']) && $package['contents']){
				$keys = array_keys($package['contents']);
				$key = $keys[0];
				$product_id = $package['contents'][$key]['product_id'];
				$product = wc_get_product($product_id);
				$product_num = $package['contents'][$key]['quantity'];
			}
			//计算产品的长宽高和重量
			if($product){
				$length = $product->get_length();
				$width =  $product->get_width();
				$height = $product->get_height();
				$weight = $product->get_weight();
			}
			$params = array(  
				'appToken' => '写你自己的',  
				'appKey' => '写你自己的',  
				'serviceMethod' => 'feetrail',  
				'paramsJson' => json_encode(array(  
					'country_code' => $package['destination']['country'],
					'post_code'=>$package['destination']['postcode'],
					'length'=>  $length ? round($length/10,2) : '',
					'width' =>  $width ? round($width/10,2) : '',
					'height'=>  $height ? round($height/10,2) : '',
					'weight' => $weight,
				))
			);
			
			// 第三方接口的URL  
			$url = 'http://ywjl.rtb56.com/webservice/PublicService.asmx/ServiceInterfaceUTF8'; // 第三方接口URL  
			// 发送请求并获取响应  
			$response = $this->send_post_request_to_third_party($url, $params);  
			if($response['code'] ==200){ 
				//处理数据: 优先可跟踪物流,其次价格最低
				$body_data = json_decode($response['body'],true);
				if(isset($body_data['success']) && $body_data['success'] == 1){
					$data_traceability =  $body_data['data'];
					if($data_traceability){
						$traceability = [];   //获取Traceability==Y的 支持物流跟踪
						foreach ($data_traceability as $key => $value) {
							if($value['Traceability'] == 'Y'){
								$traceability[] = $value;
							}
						}
						//如果都不支持物流跟踪处理,直接选择价格最低的。
						if(!$traceability){
							$final_data = $this->totalfee_orderby($data_traceability);
						}else{
							$final_data = $this->totalfee_orderby($traceability);
						}
					}
				}
			}
			//汇率价格美元 7.24
			$price = $final_data ? $final_data['TotalFee'] : 0;
			if($price >0){
				$price = round($price/7.24,2);
			}
			return array(
				// 'id' => 'custom_shipping_rate',
				'cost' => $price*$product_num, // 示例费用
			);
		}

		/**
		 * Sanitize the cost field.
		 *
		 */
		public function sanitize_cost($value)
		{
			$value = is_null($value) ? '' : $value;
			$value = wp_kses_post(trim(wp_unslash($value)));
			$value = str_replace(array(get_woocommerce_currency_symbol(), html_entity_decode(get_woocommerce_currency_symbol())), '', $value);

			return $value;
		}
		/**  
		 * 发送POST请求到第三方接口  
		 *  
		 * @param string $url 接口URL  
		 * @param array $params 请求参数  
		 * @return array|WP_Error 接口返回的数据或错误对象  
		 */
		public function send_post_request_to_third_party($url, $params) {  
			
			$response = wp_remote_post($url, array(  
				'method' => 'POST',  
				'timeout' => 45, // 设置超时时间  
				'redirection' => 5, // 设置重定向次数  
				'httpversion' => '1.1',  
				'blocking' => true,  
				'headers' => array(  
					'Content-Type' => 'application/x-www-form-urlencoded; charset=' . get_option('blog_charset'),  
				),  
				'body' => http_build_query($params), // 使用http_build_query将参数数组转换为查询字符串  
				'cookies' => array()  
			));  
			
			// 检查请求是否成功  
			if (is_wp_error($response)) {  
				// 请求失败,处理错误  
				$error_message = $response->get_error_message();  
				// 可以在这里记录错误日志或者进行其他错误处理  
				$this->save_local_post_json($error_message); //记录错误日志
				// return $response; // 返回错误对象  
				return array(  
					'code' => 500,  
					'body' => $response,  
				); 
			} else {  
				// 请求成功,返回响应数据  
				$response_code = wp_remote_retrieve_response_code($response);  
				$response_body = wp_remote_retrieve_body($response);  
				// 可以在这里进一步处理响应数据,比如解析JSON等  
				return array(  
					'code' => $response_code,  
					'body' => $response_body,  
				);  
			}  
		}  
		
		/**
		 * 保存到本地数据
		 */
		public function save_local_post_json($data){  
			// 指定文件路径  
			$file_path = __DIR__ . '/post.json';  
			  
			// 初始化一个数组来存储要保存的数据  
			$saved_data = [];  
			
			// 将当前时间戳添加到数据中  
			// $data['saved_at'] = date('Y-m-d H:i:s');  
			  
			// 将新数据添加到数组中  
			$saved_data[] = $data;  
			  
			// 将数据编码为 JSON 字符串  
			$json_data = json_encode($saved_data, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);  
			
			// 读取原文件内容  
			$file_content = '';  
			if (file_exists($file_path)) {  
				$file_content = file_get_contents($file_path);  
				$file_content = rtrim($file_content, ",\n"); // 去除末尾可能存在的逗号和换行符  
				$file_content .= ",\n"; // 添加新的记录前的逗号和换行符  
			}
			// 写入文件  
			$json_data .= date('Y-m-d H:i:s').",\n";
			$json_data .= $file_content;
			
			$success = file_put_contents($file_path, $json_data);  
			  
			if ($success) {  
				// 数据已成功保存  
				return true;  
			} else {  
				// 保存 post.json 文件时出错  
				// return false;  
			}  
		}

		/**
		 * 筛选出价格最低的物流
		 */
		public function totalfee_orderby($arrays = []){
			// 初始化最低值和对应数组  
			$minValue = PHP_INT_MAX;  
			$minArray = null; 
			// 遍历二维数组  
			foreach ($arrays as $array) {  
				// 检查当前数组中的 'value' 是否比已知的最低值还低  
				if ($array['TotalFee'] < $minValue) {  
					// 更新最低值和对应数组  
					$minValue = $array['TotalFee'];  
					$minArray = $array;  
				}  
			} 
			return $minArray;
			
		}
	}
}

function add_your_shipping_method($methods)
{
	$methods['your_shipping_method'] = 'Your_Shipping_Method';
	return $methods;
}

/**
 * 自定义物流方式 end
 */

参考文章:WooCommerce创建Shipping方法详解(2022) - sola博客 (solagirl.net)