Categories
WooCommerce Extensions

Cities Shipping Zones for WooCommerce

Which uses shop owners make with the customer city?

  • Set shipping rates per cities
  • Sales stats by city (Dashbaord => WooCommerce => Reports => Sales by city)
  • Display cities shipping calculator with the shortcode [csz_cities]
  • Sell certain products per city (with plugin that limits by state)
  • Ship certain products per city (associating the products to a class without price in shipping method which doesn’t have based price)
  • Apply taxes per city (use the city code in the state field in the tax settings)
  • Enable payment / shipping methods per city (with conditional payment / shipping plugin)
  • Shipping for cities by the day of the week (with order delivery date plugin that has shipping methods based option)
  • Display the cities in external checkout page (retreive the states via WooCommerce REST API)
Options

What is the State Autofill option?
When enabled, the state will be auto filled by the selected city for countries that have states in their cities list. You may set the countries the option will be applied on with the csz_populate_state filter.

What is the Filters option?
When enabled, a state filter will be displayed for the store country in the checkout and the shipping calculator. the state will not be inserted into the order unless the ‘State Autofill’ option is enabled.

Bulk Edit Tool

What is the required format?
Semicolon (;) between each city. For example: Wien; Rust; Steinbrunn

How to modify cities in list to the required format?
Replace [\r\n]+ (regex) with ; in Notepad++.

How to enter all the locations within certain distance from a city with distances list?
Enter exclamation mark (!) followed by the city code, if necessary add minium and maximum distance seperated by semicolon (;).

Integrations

Why in the integrated software the city appear twice or the city code is present?
You will have to remove the sending of the state field (billing/shipping, orders/customers) via its plugin’s code for the countries you apply the plugin on.

Why in my integrated software the city field is empty or the payment failed?
You will have to modify its way of retreiving the city field (billing/shipping) from the order for the countries you apply the plugin on- from: $_POST['billing_city'] into $order->get_billing_city(). As alternative, add to the woocommerce_checkout_create_order action a command that copies $order->get_billing_city() into $_POST['billing_city'].

Why the state code and not the state name appears in the order details in the first order email confirmation and in the my account section while using the State Autofill option on countries with WooCommerce built-in states list?
You may use the woocommerce_formatted_address_replacements filter to fix it.

How to prevent the loading of the cities in WCFM plugin pages?

add_filter( 'csz_enable_cities', 'csz_disable_cities_wcfm' );
add_filter( 'woocommerce_states', 'csz_load_states_wcfm', 9999 );

function csz_disable_cities_wcfm( $cities_enabled ) {
	return isset( $_GET['store-setup'] ) && 'yes' === $_GET['store-setup'] || false !== strpos( $_SERVER['REQUEST_URI'], 'store-manager' ) ? false : $cities_enabled;
}

function csz_load_states_wcfm( $states ) {
	if ( isset( $_GET['store-setup'] ) && 'yes' === $_GET['store-setup'] || false !== strpos( $_SERVER['REQUEST_URI'], 'store-manager' ) ) {
		foreach ( get_option( 'wc_csz_countries_codes' ) as $country_code ) {
			include( WP_PLUGIN_DIR . '/cities-shipping-zones-for-woocommerce/i18n/cities/' . $country_code . '.php' );
			if ( $country_states ) {
				$states[ $country_code ] = $country_states;
			}
		}
	}
	return $states;
}

How to integrate with Food Online Premium plugin?
Prevent the customer state from beeing loaded in config_default_customer_address function and add to line 836 in class-fdoe-del.php file (update the mismatch cities names):

if ( is_plugin_active( 'cities-shipping-zones-for-woocommerce/cities-shipping-zones-for-woocommerce.php' ) && in_array( $country, get_option( 'wc_csz_countries_codes' ) ) ) {
	$cities = [
		'Talin' => 'Tallinn',
	];
	if ( isset( $cities[ $_POST['city'] ] ) ) {
		$_POST['city'] = $cities[ $_POST['city'] ];
	}
	$state = array_search( _x( wc_clean( $_POST['city'] ), "{$country}-cities", 'cities-shipping-zones-for-woocommerce' ), WC()->countries->get_states( $country ) );
	$_POST['city'] = '';
}
Cities List

Why some locations are absent?
The list of most of the countries contains the municipalities, so villages within those municipalities will not be present.

How to modify cities names?
Update countries codes, and cities codes and names (not compatible with the Filters option):

add_filter( 'csz_cities', 'csz_modify_cities' );
function csz_modify_cities( $states ) {
	$states['AT']['AT90001'] = 'Vienna';
	return $states;
}

How to remove some cities from the list?
Update country code and cities codes:

add_filter( 'csz_cities', 'csz_remove_cities' );
function csz_remove_cities( $states ) {
	$country_code = 'AT';
	$unnecessary_cities = [ 'AT10101', 'AT10201', 'AT10301' ];
	foreach ( $unnecessary_cities as $city ) {
		unset( $states[ $country_code ][ $city ] );
	}
	return $states;
}

How to keep only specific cities in the list?
Update country code and cities codes:

add_filter( 'csz_cities', 'csz_set_cities' );
function csz_set_cities( $states ) {
	$country = 'AT';
	$cities = [ 'AT10101', 'AT10201', 'AT10301' ];
	$new_states = [];
	foreach ( $cities as $city ) {
		if ( isset( $states[ $country ][ $city ] ) ) {
			$new_states[ $city ] = $states[ $country ][ $city ];
		}
	}
	$states[ $country ] = $new_states;
	return $states;
}

How to remove from the list all the cities of certain states?
Update states codes:

add_filter( 'csz_states', 'csz_remove_states_cities' );
function csz_remove_states_cities( $states ) {
	$unnecessary_states = [ 'EE001', 'EE004', 'EE006' ];
	foreach ( $unnecessary_states as $state_code ) {
		if ( isset( $states[ $state_code ] ) ) {
			unset( $states[ $state_code ] );
		}
	}
	return $states;
}

How to create shipping zones for quarters inside a city?
Create shipping zone with that city and restrict to the relevant postcodes, or (not compatible with the State Autofill / Filters options and 3-party integrations) split the city into areas (update country code and city code and areas names, if the store is located inside this city update the store location in WooCommerce settings):

add_filter( 'csz_cities', 'csz_split_cities' );
function csz_split_cities( $states ) {
	$country_code = 'AT';
	$city_code = 'AT90001';
	$sub_cities = [ __( 'Northern', 'woocommerce' ), __( 'Southern', 'woocommerce' ) ];
	$count = 101;
	foreach ( $sub_cities as $sub_city ) {
		$states[ $country_code ][ $city_code . $count ] = $states[ $country_code ][ $city_code ] . ' - ' . $sub_city;
		$count++;
	}
	unset( $states[ $country_code ][ $city_code ] );
	return $states;
}

How to let the customer to select a city for the order which is not displayed in the list?
Temporary don’t apply the plugin on any country and remove all the saved states values of your current customers from those countries to prevent loading the state in the checkout city field:

add_filter( 'csz_enable_custom_city', '__return_true' );
Shortcode

How to display the shipping calculator shortocde message permanently?
Not compatible with multinational stores:

add_filter( 'wp_footer', 'csz_custom_shipping_message' );
function csz_custom_shipping_message() {
	?>
		<script type="text/javascript">
		jQuery( function( $ ) {
			$( document ).on( 'zone_matched', function( event, response ) {
				$( '#shipping_state-description' ).remove();
				if ( ! $( '#shipping_message' ).length ) {
					$( '#shipping_state_field' ).append( '<span id="shipping_message">response</span>' );
				}
				$( '#shipping_message' ).text( response );
				$( '#shipping_message' ).css( { 'color':'black', 'background-color':'yellow' } );
			} );
		} );
		</script>
	<?php
}
Distance Fee

How to apply distance fee?
Given a (domestic) city’s distances list, it will be possible to add distance based fee for the shipping rate or product price (for example- to sell moving services).

Why the tax is not calculated on the distance fee?
Enter in the shipping method cost greater than zero.

Where the configured product distance fee will be displayed?
The product the fee will be added to its price and will be displayed in the subtotal of the mini cart widget.

How I shall organize the distances list for some city?
Use as index the locations codes or names (as they appear in the dashboard and update $key_format), verify to set distance to the city itself, the distances should be greater than 0.

WooCommerce REST API

Use the class:

add_filter( 'woocommerce_rest_api_get_rest_namespaces', 'wc_states_api' );
function wc_states_api( $controllers ) {
	$controllers['wc/v3']['data-states'] = 'WC_REST_Data_States_Controller';
	return $controllers;
}

class WC_REST_Data_States_Controller extends WC_REST_Data_Controller {
	protected $namespace = 'wc/v3';
	protected $rest_base = 'data/states';
	function register_routes() {
		register_rest_route( $this->namespace, '/' . $this->rest_base . '/(?P<state>[\w-]+)/zone', [
			'methods'		=> 'GET',
			'callback'		=> [ $this, 'get_zone' ],
			'args'			=> [ 'state' => [ 'description' => __( 'State / County', 'woocommerce' ), 'type' => 'string' ] ],
			'permission_callback'	=> [ $this, 'get_items_permissions_check' ],
		] );
		register_rest_route( $this->namespace, '/' . $this->rest_base . '/(?P<state>[\w-]+)/state', [
			'methods'		=> 'GET',
			'callback'		=> [ $this, 'get_state' ],
			'args'			=> [ 'state' => [ 'description' => __( 'State / County', 'woocommerce' ), 'type' => 'string' ] ],
			'permission_callback'	=> [ $this, 'get_items_permissions_check' ],
		] );
	}
	function get_zone( $data ) {
		return [ 'id' => wc_get_shipping_zone( [ 'destination' => [ 'country' => substr( $data['state'], 0, 2 ), 'state' => $data['state'], 'postcode' => '' ] ] )->get_zone_id() ];
	}
	function get_state( $data ) {
		foreach ( get_option( 'wc_csz_countries_codes' ) as $country_code ) {
			$country_cities = '';
			$country_states = '';
			include( WP_PLUGIN_DIR . '/cities-shipping-zones-for-woocommerce/i18n/cities/' . $country_code . '.php' );
			if ( isset( $country_states ) ) {
				foreach ( $country_states as $state_code => $state_name ) {
					if ( isset( $country_cities[ $state_code ][ $data['state'] ] ) ) {
						return $country_states[ $state_code ];
					}
				}
			}
		}
		return false;
	}
}

How to retrieve the shipping zone a city belong to (for the countries the plugin apply on)?

/wp-json/wc/v3/data/states/<city_code>/zone

How to retrieve the state name a city belong to (for the countries the plugin apply on)?

/wp-json/wc/v3/data/states/<city_code>/state
Uninstall Plugin / Countries / Locations
  • WooCommerce Shipping Zones settings: Remove the locations (you may use the Bulk Edit tool)
  • Plugin Settings: Remove the countries
  • WooCommerce Settings: Update the store location
  • Users: convert/erase the state field values of users that were created/updated while the plugin was applied on the countries they belong to
  • Plugins: Deactivate and delete the plugin
Categories
WooCommerce Extensions

Default Attributes for WooCommerce

How to exclude some attribute from the stock-based default attributes calculation?
Update the attribute id:

add_filter( 'daw_max_variations', 'exclude_attribute', 10, 2 );
function exclude_attribute( $max_variations, $attribute ) {
	$excluded_attribute = 25;
	return $excluded_attribute === $attribute['id'] ? 0 : $max_variations;
}

How to apply the first attribute option only on products with less than certain amount of attributes?
Update the amount of attributes:

add_filter( 'first_attribute_checkbox', 'daw_first_attribute_restrict_products', 10, 2 );
function daw_first_attribute_restrict_products( $first_attribute_checkbox, $product ) {
	$max_attributes = 3;
	return $max_attributes < count( $product->get_attributes() ) ? 'no' : $first_attribute_checkbox;
}

How to exclude product from all the default attributes calculations?
Update the product id:

add_filter( 'daw_include_product', 'exclude_product', 10, 2 );
function exclude_product( $included, $product ) {
	$excluded_product = 71;
	return $excluded_product === $product->get_id() ? false : $included;
}
Categories
WooCommerce Extensions

Hide Address Fields for WooCommerce

How to never hide the address fields for purchase above 100?

add_filter( 'haf_hide_address', 'haf_dont_hide_address' );
function haf_dont_hide_address( $hide_enabled ) {
	return 100 <= WC()->cart->get_cart_contents_total() ? false : $hide_enabled;
}

How to make the postcode field optional for some country?
You may use the haf_optional_postcode_countries filter. Keep in mind that the built-in WooCommerce postcode validation will not be applied when using the plugin.

Categories
WooCommerce Extensions

Advanced Options for WooCommerce

How to display the amount of products items in on-hold orders instead of in proccessing orders?

add_filter( 'aow_orders', 'aow_order_status' );
function aow_order_status( $args ) {
	$args['status'] = 'on-hold';
	return $args;
}