ngtokuの日記

主に雑記帳です。SNSではngtokuのID取れなかったんで、別のIDでやってます。

Force local pickupのWooCommerce2.6対応 その2

前回の後、管理画面でzone毎の配送オプション設定をしたそうで、そしたらまたうまく動かなくなったらしいので調査。
どうやらzone設定とpickup-onlyの要素はデフォルトだとzoneで設定した配送方法の方が勝る様ですが、先方はpickup-onlyの方を強くしたいとのこと。
更にzone = LOCALShippingOK の場合で合計金額が一定金額を超える場合は、pickup-onlyでも配送料無料で配送も有効にしたいとのこと。
pickup-onlyがonlyじゃ無くなってますなってツッコミはともかくとして、調べてみました。

今回はここを参考にしてfunctions.phpを変更する事で対応しました。
https://wordpress.org/support/topic/how-to-set-certain-items-for-local-pickup-only/

<?php
/**
 * This function loops over cart items, and moves any item with shipping class 'special-class' into a new package. 
 * The new package in this example only takes flat rate shipping.
 */
function split_special_shipping_class_items( $packages ) {
	$found_item                     = false;
	$special_class                  = 'pickup-only';
	$new_package                    = current( $packages );
	$new_package['contents']        = array();
	$new_package['contents_cost']   = 0;
	$new_package['applied_coupons'] = array();
	$new_package['ship_via']        = array( 'click-and-pick_shipping_method' );
	$new_package['name'] = 'Shipping'; 
	$has_free_shipping              = false;

	foreach ( WC()->cart->get_cart() as $item_key => $item ) {
		// Is the product in the special class?
		if ( $item['data']->needs_shipping() && $special_class === $item['data']->get_shipping_class() ) {
			$found_item                            = true;
			$new_package['contents'][ $item_key ]  = $item;
			$new_package['contents_cost']         += $item['line_total'];

			// Remove from original package
			$packages[0]['contents_cost'] = $packages[0]['contents_cost'] - $item['line_total'];
			unset( $packages[0]['contents'][ $item_key ] );

			// If there are no items left in the previous package, remove it completely.
			if ( empty( $packages[0]['contents'] ) ) {
				unset( $packages[0] );
			}
		}
	}

	$ship_methods = WC()->shipping->get_shipping_methods();
	$zone_criteria['destination']['country'] = WC()->customer->get_country();
	$zone_criteria['destination']['state'] = WC()->customer->get_state();
	$zone_criteria['destination']['postcode'] = WC()->customer->get_postcode();
	$shipping_zone = WC_Shipping_Zones::get_zone_matching_package($zone_criteria);
		
	if (array_key_exists('free_shipping', $ship_methods) && strpos($shipping_zone->get_zone_name(),'LOCALShippingOK') !== false ) {
		$has_free_shipping  = true;
	}

	if ( $found_item ) {
		foreach ( WC()->cart->get_cart() as $item_key => $item ) {
			$new_package['contents'][ $item_key ]  = $item;
			$new_package['contents_cost']         += $item['line_total'];

			// Remove from original package
			$packages[0]['contents_cost'] = $packages[0]['contents_cost'] - $item['line_total'];
			unset( $packages[0]['contents'][ $item_key ] );

			// If there are no items left in the previous package, remove it completely.
			if ( empty( $packages[0]['contents'] ) ) {
		    		unset( $packages[0] );
			}
	    	}
		if ( $has_free_shipping ) {
			$new_package['ship_via'] = array('free_shipping', 'click-and-pick_shipping_method' );
		} 
	    	$packages[] = $new_package;
	}
	return $packages;
}
// Hook into shipping packages filter
add_filter( 'woocommerce_cart_shipping_packages', 'split_special_shipping_class_items' );

function rename_custom_package( $package_name, $i, $package ) {
 
    if ( ! empty( $package['name'] ) ) {
        $package_name = $package['name'];
    }
 
    return $package_name;
}
// output the new package name
add_filter( 'woocommerce_shipping_package_name', 'rename_custom_package', 10, 3 );

カート内でpickup-onlyを探すループと、配送方法再設定のループがある感じですね。
WC_Shipping_Zones::get_zone_matching_package用にわざわざ$zone_criteriaをセットせずともWC()->shippingから取れそうでしたが、
このメソッド実行時に取ろうとするとプログラムがコケるので、わざわざセットしてあります。
全体的にあまり美しくなくてモヤモヤするのですが、すでにサービスインしていて急ぎだってんで、「動くが正義」でやってみました。