id = 'tax'; $this->label = __( 'Tax', 'woocommerce' ); add_filter( 'woocommerce_settings_tabs_array', array( $this, 'add_settings_page' ), 20 ); add_action( 'woocommerce_sections_' . $this->id, array( $this, 'output_sections' ) ); add_action( 'woocommerce_settings_' . $this->id, array( $this, 'output' ) ); add_action( 'woocommerce_settings_save_' . $this->id, array( $this, 'save' ) ); } /** * Get sections * * @return array */ public function get_sections() { $sections = array( '' => __( 'Tax Options', 'woocommerce' ), 'standard' => __( 'Standard Rates', 'woocommerce' ) ); // Get tax classes and display as links $tax_classes = array_filter( array_map( 'trim', explode( "\n", get_option('woocommerce_tax_classes' ) ) ) ); if ( $tax_classes ) foreach ( $tax_classes as $class ) $sections[ sanitize_title( $class ) ] = sprintf( __( '%s Rates', 'woocommerce' ), $class ); return $sections; } /** * Get settings array * * @return array */ public function get_settings() { $tax_classes = array_filter( array_map( 'trim', explode( "\n", get_option( 'woocommerce_tax_classes' ) ) ) ); $classes_options = array(); if ( $tax_classes ) foreach ( $tax_classes as $class ) $classes_options[ sanitize_title( $class ) ] = esc_html( $class ); return apply_filters('woocommerce_tax_settings', array( array( 'title' => __( 'Tax Options', 'woocommerce' ), 'type' => 'title','desc' => '', 'id' => 'tax_options' ), array( 'title' => __( 'Enable Taxes', 'woocommerce' ), 'desc' => __( 'Enable taxes and tax calculations', 'woocommerce' ), 'id' => 'woocommerce_calc_taxes', 'default' => 'no', 'type' => 'checkbox' ), array( 'title' => __( 'Prices Entered With Tax', 'woocommerce' ), 'id' => 'woocommerce_prices_include_tax', 'default' => 'no', 'type' => 'radio', 'desc_tip' => __( 'This option is important as it will affect how you input prices. Changing it will not update existing products.', 'woocommerce' ), 'options' => array( 'yes' => __( 'Yes, I will enter prices inclusive of tax', 'woocommerce' ), 'no' => __( 'No, I will enter prices exclusive of tax', 'woocommerce' ) ), ), array( 'title' => __( 'Calculate Tax Based On:', 'woocommerce' ), 'id' => 'woocommerce_tax_based_on', 'desc_tip' => __( 'This option determines which address is used to calculate tax.', 'woocommerce' ), 'default' => 'shipping', 'type' => 'select', 'options' => array( 'shipping' => __( 'Customer shipping address', 'woocommerce' ), 'billing' => __( 'Customer billing address', 'woocommerce' ), 'base' => __( 'Shop base address', 'woocommerce' ) ), ), array( 'title' => __( 'Default Customer Address:', 'woocommerce' ), 'id' => 'woocommerce_default_customer_address', 'desc_tip' => __( 'This option determines the customers default address (before they input their own).', 'woocommerce' ), 'default' => 'base', 'type' => 'select', 'options' => array( '' => __( 'No address', 'woocommerce' ), 'base' => __( 'Shop base address', 'woocommerce' ), ), ), array( 'title' => __( 'Shipping Tax Class:', 'woocommerce' ), 'desc' => __( 'Optionally control which tax class shipping gets, or leave it so shipping tax is based on the cart items themselves.', 'woocommerce' ), 'id' => 'woocommerce_shipping_tax_class', 'css' => 'min-width:150px;', 'default' => 'title', 'type' => 'select', 'options' => array( '' => __( 'Shipping tax class based on cart items', 'woocommerce' ), 'standard' => __( 'Standard', 'woocommerce' ) ) + $classes_options, 'desc_tip' => true, ), array( 'title' => __( 'Rounding', 'woocommerce' ), 'desc' => __( 'Round tax at subtotal level, instead of rounding per line', 'woocommerce' ), 'id' => 'woocommerce_tax_round_at_subtotal', 'default' => 'no', 'type' => 'checkbox', ), array( 'title' => __( 'Additional Tax Classes', 'woocommerce' ), 'desc' => __( 'List additonal tax classes below (1 per line). This is in addition to the default Standard Rate. Tax classes can be assigned to products.', 'woocommerce' ), 'id' => 'woocommerce_tax_classes', 'css' => 'width:100%; height: 65px;', 'type' => 'textarea', 'default' => sprintf( __( 'Reduced Rate%sZero Rate', 'woocommerce' ), PHP_EOL ) ), array( 'title' => __( 'Display prices during cart/checkout:', 'woocommerce' ), 'id' => 'woocommerce_tax_display_cart', 'default' => 'excl', 'type' => 'select', 'options' => array( 'incl' => __( 'Including tax', 'woocommerce' ), 'excl' => __( 'Excluding tax', 'woocommerce' ), ), 'autoload' => false ), array( 'type' => 'sectionend', 'id' => 'tax_options' ), )); // End tax settings } /** * Output the settings */ public function output() { global $current_section; $tax_classes = array_filter( array_map( 'trim', explode( "\n", get_option('woocommerce_tax_classes' ) ) ) ); if ( $current_section == 'standard' || in_array( $current_section, array_map( 'sanitize_title', $tax_classes ) ) ) { $this->output_tax_rates(); } else { $settings = $this->get_settings(); WC_Admin_Settings::output_fields( $settings ); } } /** * Save settings */ public function save() { global $current_section; if ( ! $current_section ) { $settings = $this->get_settings(); WC_Admin_Settings::save_fields( $settings ); } else { $this->save_tax_rates(); } } /** * Output tax rate tables */ public function output_tax_rates() { global $woocommerce, $current_section, $wpdb; $tax_classes = array_filter( array_map( 'trim', explode( "\n", get_option('woocommerce_tax_classes' ) ) ) ); $current_class = ''; foreach( $tax_classes as $class ) if ( sanitize_title( $class ) == $current_section ) $current_class = $class; ?>

See here for available alpha-2 country codes.', 'woocommerce' ), 'http://en.wikipedia.org/wiki/ISO_3166-1#Current_codes' ); ?>

get_results( $wpdb->prepare( "SELECT * FROM {$wpdb->prefix}woocommerce_tax_rates WHERE tax_rate_class = %s ORDER BY tax_rate_order " , sanitize_title( $current_class ) ) ); foreach ( $rates as $rate ) { ?>
   [?]  [?]  [?]  [?]  [?]  [?]  [?]  [?]  [?]
prefix}woocommerce_tax_rate_locations WHERE location_type='postcode' AND tax_rate_id = %d ORDER BY location_code", $rate->tax_rate_id ) ); echo esc_attr( implode( '; ', $locations ) ); ?>" placeholder="*" data-name="tax_rate_postcode[tax_rate_id ?>]" /> prefix}woocommerce_tax_rate_locations WHERE location_type='city' AND tax_rate_id = %d ORDER BY location_code", $rate->tax_rate_id ) ); echo esc_attr( implode( '; ', $locations ) ); ?>" placeholder="*" data-name="tax_rate_city[tax_rate_id ?>]" /> tax_rate_compound, '1' ); ?> /> tax_rate_shipping, '1' ); ?> />
$value ) { // new keys are inserted... if ( $key == 'new' ) { foreach ( $value as $new_key => $new_value ) { // Sanitize + format $country = strtoupper( woocommerce_clean( $tax_rate_country[ $key ][ $new_key ] ) ); $state = strtoupper( woocommerce_clean( $tax_rate_state[ $key ][ $new_key ] ) ); $postcode = woocommerce_clean( $tax_rate_postcode[ $key ][ $new_key ] ); $city = woocommerce_clean( $tax_rate_city[ $key ][ $new_key ] ); $rate = number_format( woocommerce_clean( $tax_rate[ $key ][ $new_key ] ), 4, '.', '' ); $name = woocommerce_clean( $tax_rate_name[ $key ][ $new_key ] ); $priority = absint( woocommerce_clean( $tax_rate_priority[ $key ][ $new_key ] ) ); $compound = isset( $tax_rate_compound[ $key ][ $new_key ] ) ? 1 : 0; $shipping = isset( $tax_rate_shipping[ $key ][ $new_key ] ) ? 1 : 0; if ( ! $name ) $name = __( 'Tax', 'woocommerce' ); if ( $country == '*' ) $country = ''; if ( $state == '*' ) $state = ''; $wpdb->insert( $wpdb->prefix . "woocommerce_tax_rates", array( 'tax_rate_country' => $country, 'tax_rate_state' => $state, 'tax_rate' => $rate, 'tax_rate_name' => $name, 'tax_rate_priority' => $priority, 'tax_rate_compound' => $compound, 'tax_rate_shipping' => $shipping, 'tax_rate_order' => $i, 'tax_rate_class' => sanitize_title( $current_class ) ) ); $tax_rate_id = $wpdb->insert_id; if ( ! empty( $postcode ) ) { $postcodes = explode( ';', $postcode ); $postcodes = array_map( 'strtoupper', array_map( 'woocommerce_clean', $postcodes ) ); $postcode_query = array(); foreach( $postcodes as $postcode ) if ( strstr( $postcode, '-' ) ) { $postcode_parts = explode( '-', $postcode ); if ( is_numeric( $postcode_parts[0] ) && is_numeric( $postcode_parts[1] ) && $postcode_parts[1] > $postcode_parts[0] ) { for ( $i = $postcode_parts[0]; $i <= $postcode_parts[1]; $i ++ ) { if ( $i ) $postcode_query[] = "( '" . $wpdb->escape( $i ) . "', $tax_rate_id, 'postcode' )"; } } } else { if ( $postcode ) $postcode_query[] = "( '" . $wpdb->escape( $postcode ) . "', $tax_rate_id, 'postcode' )"; } $wpdb->query( "INSERT INTO {$wpdb->prefix}woocommerce_tax_rate_locations ( location_code, tax_rate_id, location_type ) VALUES " . implode( ',', $postcode_query ) ); } if ( ! empty( $city ) ) { $cities = explode( ';', $city ); $cities = array_map( 'strtoupper', array_map( 'woocommerce_clean', $cities ) ); foreach( $cities as $city ) { $wpdb->insert( $wpdb->prefix . "woocommerce_tax_rate_locations", array( 'location_code' => $city, 'tax_rate_id' => $tax_rate_id, 'location_type' => 'city', ) ); } } $i++; } // ...whereas the others are updated } else { $tax_rate_id = absint( $key ); if ( $_POST['remove_tax_rate'][ $key ] == 1 ) { $wpdb->query( $wpdb->prepare( "DELETE FROM {$wpdb->prefix}woocommerce_tax_rate_locations WHERE tax_rate_id = %d;", $tax_rate_id ) ); $wpdb->query( $wpdb->prepare( "DELETE FROM {$wpdb->prefix}woocommerce_tax_rates WHERE tax_rate_id = %d;", $tax_rate_id ) ); continue; } // Sanitize + format $country = strtoupper( woocommerce_clean( $tax_rate_country[ $key ] ) ); $state = strtoupper( woocommerce_clean( $tax_rate_state[ $key ] ) ); $rate = number_format( woocommerce_clean( $tax_rate[ $key ] ), 4, '.', '' ); $name = woocommerce_clean( $tax_rate_name[ $key ] ); $priority = absint( woocommerce_clean( $tax_rate_priority[ $key ] ) ); $compound = isset( $tax_rate_compound[ $key ] ) ? 1 : 0; $shipping = isset( $tax_rate_shipping[ $key ] ) ? 1 : 0; if ( ! $name ) $name = __( 'Tax', 'woocommerce' ); if ( $country == '*' ) $country = ''; if ( $state == '*' ) $state = ''; $wpdb->update( $wpdb->prefix . "woocommerce_tax_rates", array( 'tax_rate_country' => $country, 'tax_rate_state' => $state, 'tax_rate' => $rate, 'tax_rate_name' => $name, 'tax_rate_priority' => $priority, 'tax_rate_compound' => $compound, 'tax_rate_shipping' => $shipping, 'tax_rate_order' => $i, 'tax_rate_class' => sanitize_title( $current_class ) ), array( 'tax_rate_id' => $tax_rate_id ) ); if ( isset( $tax_rate_postcode[ $key ] ) ) { // Delete old $wpdb->query( $wpdb->prepare( "DELETE FROM {$wpdb->prefix}woocommerce_tax_rate_locations WHERE tax_rate_id = %d AND location_type = 'postcode';", $tax_rate_id ) ); // Add changed $postcode = woocommerce_clean( $tax_rate_postcode[ $key ] ); $postcodes = explode( ';', $postcode ); $postcodes = array_map( 'strtoupper', array_map( 'woocommerce_clean', $postcodes ) ); $postcode_query = array(); foreach( $postcodes as $postcode ) if ( strstr( $postcode, '-' ) ) { $postcode_parts = explode( '-', $postcode ); if ( is_numeric( $postcode_parts[0] ) && is_numeric( $postcode_parts[1] ) && $postcode_parts[1] > $postcode_parts[0] ) { for ( $i = $postcode_parts[0]; $i <= $postcode_parts[1]; $i ++ ) { if ( $i ) $postcode_query[] = "( '" . $wpdb->escape( $i ) . "', $tax_rate_id, 'postcode' )"; } } } else { if ( $postcode ) $postcode_query[] = "( '" . $wpdb->escape( $postcode ) . "', $tax_rate_id, 'postcode' )"; } $wpdb->query( "INSERT INTO {$wpdb->prefix}woocommerce_tax_rate_locations ( location_code, tax_rate_id, location_type ) VALUES " . implode( ',', $postcode_query ) ); } if ( isset( $tax_rate_city[ $key ] ) ) { // Delete old $wpdb->query( $wpdb->prepare( "DELETE FROM {$wpdb->prefix}woocommerce_tax_rate_locations WHERE tax_rate_id = %d AND location_type = 'city';", $tax_rate_id ) ); // Add changed $city = woocommerce_clean( $tax_rate_city[ $key ] ); $cities = explode( ';', $city ); $cities = array_map( 'strtoupper', array_map( 'woocommerce_clean', $cities ) ); foreach( $cities as $city ) { if ( $city ) { $wpdb->insert( $wpdb->prefix . "woocommerce_tax_rate_locations", array( 'location_code' => $city, 'tax_rate_id' => $tax_rate_id, 'location_type' => 'city', ) ); } } } $i++; } } } } endif; return new WC_Settings_Tax();