PageRenderTime 56ms CodeModel.GetById 26ms RepoModel.GetById 0ms app.codeStats 0ms

/admin/settings/settings-tax-rates.php

https://github.com/alexcsandru/woocommerce
PHP | 547 lines | 418 code | 97 blank | 32 comment | 62 complexity | 88b6359aebcb74d0dd6b56faf85e3d49 MD5 | raw file
Possible License(s): GPL-3.0
  1. <?php
  2. /**
  3. * Additional tax settings
  4. *
  5. * @author WooThemes
  6. * @category Admin
  7. * @package WooCommerce/Admin/Settings
  8. * @version 2.0.0
  9. */
  10. if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
  11. /**
  12. * Output tax rate settings.
  13. *
  14. * @access public
  15. * @return void
  16. */
  17. function woocommerce_tax_rates_setting() {
  18. global $woocommerce, $current_section, $wpdb;
  19. $tax_classes = array_filter( array_map( 'trim', explode( "\n", get_option('woocommerce_tax_classes' ) ) ) );
  20. $current_class = '';
  21. foreach( $tax_classes as $class )
  22. if ( sanitize_title( $class ) == $current_section )
  23. $current_class = $class;
  24. ?>
  25. <h3><?php printf( __( 'Tax Rates for the "%s" Class', 'woocommerce' ), $current_class ? esc_html( $current_class ) : __( 'Standard', 'woocommerce' ) ); ?></h3>
  26. <p><?php printf( __( 'Define tax rates for countries and states below. <a href="%s">See here</a> for available alpha-2 country codes.', 'woocommerce' ), 'http://en.wikipedia.org/wiki/ISO_3166-1#Current_codes' ); ?></p>
  27. <table class="wc_tax_rates widefat">
  28. <thead>
  29. <tr>
  30. <th class="sort">&nbsp;</th>
  31. <th width="8%"><?php _e( 'Country&nbsp;Code', 'woocommerce' ); ?>&nbsp;<span class="tips" data-tip="<?php _e('A 2 digit country code, e.g. US. Leave blank to apply to all.', 'woocommerce'); ?>">[?]</span></th>
  32. <th width="8%"><?php _e( 'State&nbsp;Code', 'woocommerce' ); ?>&nbsp;<span class="tips" data-tip="<?php _e('A 2 digit state code, e.g. AL. Leave blank to apply to all.', 'woocommerce'); ?>">[?]</span></th>
  33. <th><?php _e( 'ZIP/Postcode', 'woocommerce' ); ?>&nbsp;<span class="tips" data-tip="<?php _e('Postcode for this rule. Semi-colon (;) separate multiple values. Leave blank to apply to all areas. Wildcards (*) can be used. Ranges for numeric postcodes (e.g. 12345-12350) will be expanded into individual postcodes.', 'woocommerce'); ?>">[?]</span></th>
  34. <th><?php _e( 'City', 'woocommerce' ); ?>&nbsp;<span class="tips" data-tip="<?php _e('Cities for this rule. Semi-colon (;) separate multiple values. Leave blank to apply to all cities.', 'woocommerce'); ?>">[?]</span></th>
  35. <th width="8%"><?php _e( 'Rate&nbsp;%', 'woocommerce' ); ?>&nbsp;<span class="tips" data-tip="<?php _e( 'Enter a tax rate (percentage) to 4 decimal places.', 'woocommerce' ); ?>">[?]</span></th>
  36. <th width="8%"><?php _e( 'Tax&nbsp;Name', 'woocommerce' ); ?>&nbsp;<span class="tips" data-tip="<?php _e('Enter a name for this tax rate.', 'woocommerce'); ?>">[?]</span></th>
  37. <th width="8%"><?php _e( 'Priority', 'woocommerce' ); ?>&nbsp;<span class="tips" data-tip="<?php _e('Choose a priority for this tax rate. Only 1 matching rate per priority will be used. To define multiple tax rates for a single area you need to specify a different priority per rate.', 'woocommerce'); ?>">[?]</span></th>
  38. <th width="8%"><?php _e( 'Compound', 'woocommerce' ); ?>&nbsp;<span class="tips" data-tip="<?php _e('Choose whether or not this is a compound rate. Compound tax rates are applied on top of other tax rates.', 'woocommerce'); ?>">[?]</span></th>
  39. <th width="8%"><?php _e( 'Shipping', 'woocommerce' ); ?>&nbsp;<span class="tips" data-tip="<?php _e('Choose whether or not this tax rate also gets applied to shipping.', 'woocommerce'); ?>">[?]</span></th>
  40. </tr>
  41. </thead>
  42. <tfoot>
  43. <tr>
  44. <th colspan="10">
  45. <a href="#" class="button plus insert"><?php _e( 'Insert row', 'woocommerce' ); ?></a>
  46. <a href="#" class="button minus remove"><?php _e( 'Remove selected row(s)', 'woocommerce' ); ?></a>
  47. <a href="#" download="tax_rates.csv" class="button export"><?php _e( 'Export CSV', 'woocommerce' ); ?></a>
  48. <a href="<?php echo admin_url( 'admin.php?import=woocommerce_tax_rate_csv' ); ?>" class="button import"><?php _e( 'Import CSV', 'woocommerce' ); ?></a>
  49. </th>
  50. </tr>
  51. </tfoot>
  52. <tbody id="rates">
  53. <?php
  54. $rates = $wpdb->get_results( $wpdb->prepare(
  55. "SELECT * FROM {$wpdb->prefix}woocommerce_tax_rates
  56. WHERE tax_rate_class = %s
  57. ORDER BY tax_rate_order
  58. " , sanitize_title( $current_class ) ) );
  59. foreach ( $rates as $rate ) {
  60. ?>
  61. <tr>
  62. <td class="sort"><input type="hidden" class="remove_tax_rate" name="remove_tax_rate[<?php echo $rate->tax_rate_id ?>]" value="0" /></td>
  63. <td class="country" width="8%">
  64. <input type="text" value="<?php echo esc_attr( $rate->tax_rate_country ) ?>" placeholder="*" name="tax_rate_country[<?php echo $rate->tax_rate_id ?>]" />
  65. </td>
  66. <td class="state" width="8%">
  67. <input type="text" value="<?php echo esc_attr( $rate->tax_rate_state ) ?>" placeholder="*" name="tax_rate_state[<?php echo $rate->tax_rate_id ?>]" />
  68. </td>
  69. <td class="postcode">
  70. <input type="text" value="<?php
  71. $locations = $wpdb->get_col( $wpdb->prepare( "SELECT location_code FROM {$wpdb->prefix}woocommerce_tax_rate_locations WHERE location_type='postcode' AND tax_rate_id = %d ORDER BY location_code", $rate->tax_rate_id ) );
  72. echo esc_attr( implode( '; ', $locations ) );
  73. ?>" placeholder="*" data-name="tax_rate_postcode[<?php echo $rate->tax_rate_id ?>]" />
  74. </td>
  75. <td class="city">
  76. <input type="text" value="<?php
  77. $locations = $wpdb->get_col( $wpdb->prepare( "SELECT location_code FROM {$wpdb->prefix}woocommerce_tax_rate_locations WHERE location_type='city' AND tax_rate_id = %d ORDER BY location_code", $rate->tax_rate_id ) );
  78. echo esc_attr( implode( '; ', $locations ) );
  79. ?>" placeholder="*" data-name="tax_rate_city[<?php echo $rate->tax_rate_id ?>]" />
  80. </td>
  81. <td class="rate" width="8%">
  82. <input type="number" step="any" min="0" value="<?php echo esc_attr( $rate->tax_rate ) ?>" placeholder="0" name="tax_rate[<?php echo $rate->tax_rate_id ?>]" />
  83. </td>
  84. <td class="name" width="8%">
  85. <input type="text" value="<?php echo esc_attr( $rate->tax_rate_name ) ?>" name="tax_rate_name[<?php echo $rate->tax_rate_id ?>]" />
  86. </td>
  87. <td class="priority" width="8%">
  88. <input type="number" step="1" min="1" value="<?php echo esc_attr( $rate->tax_rate_priority ) ?>" name="tax_rate_priority[<?php echo $rate->tax_rate_id ?>]" />
  89. </td>
  90. <td class="compound" width="8%">
  91. <input type="checkbox" class="checkbox" name="tax_rate_compound[<?php echo $rate->tax_rate_id ?>]" <?php checked( $rate->tax_rate_compound, '1' ); ?> />
  92. </td>
  93. <td class="apply_to_shipping" width="8%">
  94. <input type="checkbox" class="checkbox" name="tax_rate_shipping[<?php echo $rate->tax_rate_id ?>]" <?php checked($rate->tax_rate_shipping, '1' ); ?> />
  95. </td>
  96. </tr>
  97. <?php
  98. }
  99. ?>
  100. </tbody>
  101. </table>
  102. <script type="text/javascript">
  103. jQuery( function() {
  104. jQuery('.wc_tax_rates tbody').sortable({
  105. items:'tr',
  106. cursor:'move',
  107. axis:'y',
  108. scrollSensitivity:40,
  109. forcePlaceholderSize: true,
  110. helper: 'clone',
  111. opacity: 0.65,
  112. placeholder: 'wc-metabox-sortable-placeholder',
  113. start:function(event,ui){
  114. ui.item.css('background-color','#f6f6f6');
  115. },
  116. stop:function(event,ui){
  117. ui.item.removeAttr('style');
  118. }
  119. });
  120. jQuery('.wc_tax_rates .remove').click(function() {
  121. var $tbody = jQuery('.wc_tax_rates').find('tbody');
  122. if ( $tbody.find('tr.current').size() > 0 ) {
  123. $current = $tbody.find('tr.current');
  124. $current.find('input').val('');
  125. $current.find('input.remove_tax_rate').val('1');
  126. $current.each(function(){
  127. if ( jQuery(this).is('.new') )
  128. jQuery(this).remove();
  129. else
  130. jQuery(this).hide();
  131. });
  132. } else {
  133. alert('<?php _e( 'No row(s) selected', 'woocommerce' ); ?>');
  134. }
  135. return false;
  136. });
  137. var controlled = false;
  138. var shifted = false;
  139. var hasFocus = false;
  140. jQuery(document).bind('keyup keydown', function(e){ shifted = e.shiftKey; controlled = e.ctrlKey || e.metaKey } );
  141. jQuery('#rates').on( 'focus click', 'input', function( e ) {
  142. $this_row = jQuery(this).closest('tr');
  143. if ( ( e.type == 'focus' && hasFocus != $this_row.index() ) || ( e.type == 'click' && jQuery(this).is(':focus') ) ) {
  144. hasFocus = $this_row.index();
  145. if ( ! shifted && ! controlled ) {
  146. jQuery('#rates tr').removeClass('current').removeClass('last_selected');
  147. $this_row.addClass('current').addClass('last_selected');
  148. } else if ( shifted ) {
  149. jQuery('#rates tr').removeClass('current');
  150. $this_row.addClass('selected_now').addClass('current');
  151. if ( jQuery('#rates tr.last_selected').size() > 0 ) {
  152. if ( $this_row.index() > jQuery('#rates tr.last_selected').index() ) {
  153. jQuery('#rates tr').slice( jQuery('#rates tr.last_selected').index(), $this_row.index() ).addClass('current');
  154. } else {
  155. jQuery('#rates tr').slice( $this_row.index(), jQuery('#rates tr.last_selected').index() + 1 ).addClass('current');
  156. }
  157. }
  158. jQuery('#rates tr').removeClass('last_selected');
  159. $this_row.addClass('last_selected');
  160. } else {
  161. jQuery('#rates tr').removeClass('last_selected');
  162. if ( controlled && jQuery(this).closest('tr').is('.current') ) {
  163. $this_row.removeClass('current');
  164. } else {
  165. $this_row.addClass('current').addClass('last_selected');
  166. }
  167. }
  168. jQuery('#rates tr').removeClass('selected_now');
  169. }
  170. }).on( 'blur', 'input', function( e ) {
  171. hasFocus = false;
  172. });
  173. jQuery('.wc_tax_rates .export').click(function() {
  174. var csv_data = "data:application/csv;charset=utf-8,<?php _e( 'Country Code', 'woocommerce' ); ?>,<?php _e( 'State Code', 'woocommerce' ); ?>,<?php _e( 'ZIP/Postcode', 'woocommerce' ); ?>,<?php _e( 'City', 'woocommerce' ); ?>,<?php _e( 'Rate %', 'woocommerce' ); ?>,<?php _e( 'Tax Name', 'woocommerce' ); ?>,<?php _e( 'Priority', 'woocommerce' ); ?>,<?php _e( 'Compound', 'woocommerce' ); ?>,<?php _e( 'Shipping', 'woocommerce' ); ?>,<?php _e( 'Tax Class', 'woocommerce' ); ?>\n";
  175. jQuery('#rates tr:visible').each(function() {
  176. var row = '';
  177. jQuery(this).find('td:not(.sort) input').each(function() {
  178. if ( jQuery(this).is('.checkbox') ) {
  179. if ( jQuery(this).is(':checked') ) {
  180. val = 1;
  181. } else {
  182. val = 0;
  183. }
  184. } else {
  185. var val = jQuery(this).val();
  186. if ( ! val )
  187. val = jQuery(this).attr('placeholder');
  188. }
  189. row = row + val + ',';
  190. });
  191. row = row + '<?php echo $current_class; ?>';
  192. //row.substring( 0, row.length - 1 );
  193. csv_data = csv_data + row + "\n";
  194. });
  195. jQuery(this).attr( 'href', encodeURI( csv_data ) );
  196. return true;
  197. });
  198. jQuery('.wc_tax_rates .insert').click(function() {
  199. var $tbody = jQuery('.wc_tax_rates').find('tbody');
  200. var size = $tbody.find('tr').size();
  201. var code = '<tr class="new">\
  202. <td class="sort">&nbsp;</td>\
  203. <td class="country" width="8%">\
  204. <input type="text" placeholder="*" name="tax_rate_country[new][' + size + ']" />\
  205. </td>\
  206. <td class="state" width="8%">\
  207. <input type="text" placeholder="*" name="tax_rate_state[new][' + size + ']" />\
  208. </td>\
  209. <td class="postcode">\
  210. <input type="text" placeholder="*" name="tax_rate_postcode[new][' + size + ']" />\
  211. </td>\
  212. <td class="city">\
  213. <input type="text" placeholder="*" name="tax_rate_city[new][' + size + ']" />\
  214. </td>\
  215. <td class="rate" width="8%">\
  216. <input type="number" step="any" min="0" placeholder="0" name="tax_rate[new][' + size + ']" />\
  217. </td>\
  218. <td class="name" width="8%">\
  219. <input type="text" name="tax_rate_name[new][' + size + ']" />\
  220. </td>\
  221. <td class="priority" width="8%">\
  222. <input type="number" step="1" min="1" value="1" name="tax_rate_priority[new][' + size + ']" />\
  223. </td>\
  224. <td class="compound" width="8%">\
  225. <input type="checkbox" class="checkbox" name="tax_rate_compound[new][' + size + ']" />\
  226. </td>\
  227. <td class="apply_to_shipping" width="8%">\
  228. <input type="checkbox" class="checkbox" name="tax_rate_shipping[new][' + size + ']" checked="checked" />\
  229. </td>\
  230. </tr>';
  231. if ( $tbody.find('tr.current').size() > 0 ) {
  232. $tbody.find('tr.current').after( code );
  233. } else {
  234. $tbody.append( code );
  235. }
  236. jQuery( "td.country input" ).autocomplete({
  237. source: availableCountries,
  238. minLength: 3
  239. });
  240. jQuery( "td.state input" ).autocomplete({
  241. source: availableStates,
  242. minLength: 3
  243. });
  244. return false;
  245. });
  246. jQuery('.wc_tax_rates td.postcode, .wc_tax_rates td.city').find('input').change(function() {
  247. jQuery(this).attr( 'name', jQuery(this).attr( 'data-name' ) );
  248. });
  249. var availableCountries = [<?php
  250. $countries = array();
  251. foreach ( $woocommerce->countries->get_allowed_countries() as $value => $label )
  252. $countries[] = '{ label: "' . $label . '", value: "' . $value . '" }';
  253. echo implode( ', ', $countries );
  254. ?>];
  255. var availableStates = [<?php
  256. $countries = array();
  257. foreach ( $woocommerce->countries->get_allowed_country_states() as $value => $label )
  258. foreach ( $label as $code => $state )
  259. $countries[] = '{ label: "' . $state . '", value: "' . $code . '" }';
  260. echo implode( ', ', $countries );
  261. ?>];
  262. jQuery( "td.country input" ).autocomplete({
  263. source: availableCountries,
  264. minLength: 3
  265. });
  266. jQuery( "td.state input" ).autocomplete({
  267. source: availableStates,
  268. minLength: 3
  269. });
  270. });
  271. </script>
  272. <?php
  273. }
  274. /**
  275. * woocommerce_tax_rates_setting_save function.
  276. *
  277. * @access public
  278. * @return void
  279. */
  280. function woocommerce_tax_rates_setting_save() {
  281. global $wpdb, $current_section;
  282. // Get class
  283. $tax_classes = array_filter( array_map( 'trim', explode( "\n", get_option('woocommerce_tax_classes' ) ) ) );
  284. $current_class = '';
  285. foreach( $tax_classes as $class )
  286. if ( sanitize_title( $class ) == $current_section )
  287. $current_class = $class;
  288. // Get POST data
  289. $tax_rate_country = isset( $_POST['tax_rate_country'] ) ? $_POST['tax_rate_country'] : array();
  290. $tax_rate_state = isset( $_POST['tax_rate_state'] ) ? $_POST['tax_rate_state'] : array();
  291. $tax_rate_postcode = isset( $_POST['tax_rate_postcode'] ) ? $_POST['tax_rate_postcode'] : array();
  292. $tax_rate_city = isset( $_POST['tax_rate_city'] ) ? $_POST['tax_rate_city'] : array();
  293. $tax_rate = isset( $_POST['tax_rate'] ) ? $_POST['tax_rate'] : array();
  294. $tax_rate_name = isset( $_POST['tax_rate_name'] ) ? $_POST['tax_rate_name'] : array();
  295. $tax_rate_priority = isset( $_POST['tax_rate_priority'] ) ? $_POST['tax_rate_priority'] : array();
  296. $tax_rate_compound = isset( $_POST['tax_rate_compound'] ) ? $_POST['tax_rate_compound'] : array();
  297. $tax_rate_shipping = isset( $_POST['tax_rate_shipping'] ) ? $_POST['tax_rate_shipping'] : array();
  298. $i = 0;
  299. // Loop posted fields
  300. foreach ( $tax_rate_country as $key => $value ) {
  301. // new keys are inserted...
  302. if ( $key == 'new' ) {
  303. foreach ( $value as $new_key => $new_value ) {
  304. // Sanitize + format
  305. $country = strtoupper( woocommerce_clean( $tax_rate_country[ $key ][ $new_key ] ) );
  306. $state = strtoupper( woocommerce_clean( $tax_rate_state[ $key ][ $new_key ] ) );
  307. $postcode = woocommerce_clean( $tax_rate_postcode[ $key ][ $new_key ] );
  308. $city = woocommerce_clean( $tax_rate_city[ $key ][ $new_key ] );
  309. $rate = number_format( woocommerce_clean( $tax_rate[ $key ][ $new_key ] ), 4, '.', '' );
  310. $name = woocommerce_clean( $tax_rate_name[ $key ][ $new_key ] );
  311. $priority = absint( woocommerce_clean( $tax_rate_priority[ $key ][ $new_key ] ) );
  312. $compound = isset( $tax_rate_compound[ $key ][ $new_key ] ) ? 1 : 0;
  313. $shipping = isset( $tax_rate_shipping[ $key ][ $new_key ] ) ? 1 : 0;
  314. if ( ! $name )
  315. $name = __( 'Tax', 'woocommerce' );
  316. if ( $country == '*' )
  317. $country = '';
  318. if ( $state == '*' )
  319. $state = '';
  320. $wpdb->insert(
  321. $wpdb->prefix . "woocommerce_tax_rates",
  322. array(
  323. 'tax_rate_country' => $country,
  324. 'tax_rate_state' => $state,
  325. 'tax_rate' => $rate,
  326. 'tax_rate_name' => $name,
  327. 'tax_rate_priority' => $priority,
  328. 'tax_rate_compound' => $compound,
  329. 'tax_rate_shipping' => $shipping,
  330. 'tax_rate_order' => $i,
  331. 'tax_rate_class' => sanitize_title( $current_class )
  332. )
  333. );
  334. $tax_rate_id = $wpdb->insert_id;
  335. if ( ! empty( $postcode ) ) {
  336. $postcodes = explode( ';', $postcode );
  337. $postcodes = array_map( 'strtoupper', array_map( 'woocommerce_clean', $postcodes ) );
  338. foreach( $postcodes as $postcode ) {
  339. $wpdb->insert(
  340. $wpdb->prefix . "woocommerce_tax_rate_locations",
  341. array(
  342. 'location_code' => $postcode,
  343. 'tax_rate_id' => $tax_rate_id,
  344. 'location_type' => 'postcode',
  345. )
  346. );
  347. }
  348. }
  349. if ( ! empty( $city ) ) {
  350. $cities = explode( ';', $city );
  351. $cities = array_map( 'strtoupper', array_map( 'woocommerce_clean', $cities ) );
  352. foreach( $cities as $city ) {
  353. $wpdb->insert(
  354. $wpdb->prefix . "woocommerce_tax_rate_locations",
  355. array(
  356. 'location_code' => $city,
  357. 'tax_rate_id' => $tax_rate_id,
  358. 'location_type' => 'city',
  359. )
  360. );
  361. }
  362. }
  363. $i++;
  364. }
  365. // ...whereas the others are updated
  366. } else {
  367. $tax_rate_id = absint( $key );
  368. if ( $_POST['remove_tax_rate'][ $key ] == 1 ) {
  369. $wpdb->query( $wpdb->prepare( "DELETE FROM {$wpdb->prefix}woocommerce_tax_rate_locations WHERE tax_rate_id = %d;", $tax_rate_id ) );
  370. $wpdb->query( $wpdb->prepare( "DELETE FROM {$wpdb->prefix}woocommerce_tax_rates WHERE tax_rate_id = %d;", $tax_rate_id ) );
  371. continue;
  372. }
  373. // Sanitize + format
  374. $country = strtoupper( woocommerce_clean( $tax_rate_country[ $key ] ) );
  375. $state = strtoupper( woocommerce_clean( $tax_rate_state[ $key ] ) );
  376. $rate = number_format( woocommerce_clean( $tax_rate[ $key ] ), 4, '.', '' );
  377. $name = woocommerce_clean( $tax_rate_name[ $key ] );
  378. $priority = absint( woocommerce_clean( $tax_rate_priority[ $key ] ) );
  379. $compound = isset( $tax_rate_compound[ $key ] ) ? 1 : 0;
  380. $shipping = isset( $tax_rate_shipping[ $key ] ) ? 1 : 0;
  381. if ( ! $name )
  382. $name = __( 'Tax', 'woocommerce' );
  383. if ( $country == '*' )
  384. $country = '';
  385. if ( $state == '*' )
  386. $state = '';
  387. $wpdb->update(
  388. $wpdb->prefix . "woocommerce_tax_rates",
  389. array(
  390. 'tax_rate_country' => $country,
  391. 'tax_rate_state' => $state,
  392. 'tax_rate' => $rate,
  393. 'tax_rate_name' => $name,
  394. 'tax_rate_priority' => $priority,
  395. 'tax_rate_compound' => $compound,
  396. 'tax_rate_shipping' => $shipping,
  397. 'tax_rate_order' => $i,
  398. 'tax_rate_class' => sanitize_title( $current_class )
  399. ),
  400. array(
  401. 'tax_rate_id' => $tax_rate_id
  402. )
  403. );
  404. if ( isset( $tax_rate_postcode[ $key ] ) ) {
  405. // Delete old
  406. $wpdb->query( $wpdb->prepare( "DELETE FROM {$wpdb->prefix}woocommerce_tax_rate_locations WHERE tax_rate_id = %d AND location_type = 'postcode';", $tax_rate_id ) );
  407. // Add changed
  408. $postcode = woocommerce_clean( $tax_rate_postcode[ $key ] );
  409. $postcodes = explode( ';', $postcode );
  410. $postcodes = array_map( 'strtoupper', array_map( 'woocommerce_clean', $postcodes ) );
  411. $postcode_query = array();
  412. foreach( $postcodes as $postcode )
  413. if ( strstr( $postcode, '-' ) ) {
  414. $postcode_parts = explode( '-', $postcode );
  415. if ( is_numeric( $postcode_parts[0] ) && is_numeric( $postcode_parts[1] ) && $postcode_parts[1] > $postcode_parts[0] ) {
  416. for ( $i = $postcode_parts[0]; $i <= $postcode_parts[1]; $i ++ ) {
  417. if ( $i )
  418. $postcode_query[] = "( '$i', $tax_rate_id, 'postcode' )";
  419. }
  420. }
  421. } else {
  422. if ( $postcode )
  423. $postcode_query[] = "( '$postcode', $tax_rate_id, 'postcode' )";
  424. }
  425. $wpdb->query( "INSERT INTO {$wpdb->prefix}woocommerce_tax_rate_locations ( location_code, tax_rate_id, location_type ) VALUES " . implode( ',', $postcode_query ) );
  426. }
  427. if ( isset( $tax_rate_city[ $key ] ) ) {
  428. // Delete old
  429. $wpdb->query( $wpdb->prepare( "DELETE FROM {$wpdb->prefix}woocommerce_tax_rate_locations WHERE tax_rate_id = %d AND location_type = 'city';", $tax_rate_id ) );
  430. // Add changed
  431. $city = woocommerce_clean( $tax_rate_city[ $key ] );
  432. $cities = explode( ';', $city );
  433. $cities = array_map( 'strtoupper', array_map( 'woocommerce_clean', $cities ) );
  434. foreach( $cities as $city ) {
  435. if ( $city ) {
  436. $wpdb->insert(
  437. $wpdb->prefix . "woocommerce_tax_rate_locations",
  438. array(
  439. 'location_code' => $city,
  440. 'tax_rate_id' => $tax_rate_id,
  441. 'location_type' => 'city',
  442. )
  443. );
  444. }
  445. }
  446. }
  447. $i++;
  448. }
  449. }
  450. }