PageRenderTime 30ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 0ms

/wp-content/plugins/woocommerce/includes/admin/settings/class-wc-settings-tax.php

https://gitlab.com/campus-academy/krowkaramel
PHP | 348 lines | 221 code | 49 blank | 78 comment | 19 complexity | cc1b51e82d098cb15189f77b30c40915 MD5 | raw file
  1. <?php
  2. /**
  3. * WooCommerce Tax Settings
  4. *
  5. * @package WooCommerce\Admin
  6. * @version 2.1.0
  7. */
  8. if ( ! defined( 'ABSPATH' ) ) {
  9. exit;
  10. }
  11. if ( class_exists( 'WC_Settings_Tax', false ) ) {
  12. return new WC_Settings_Tax();
  13. }
  14. /**
  15. * WC_Settings_Tax.
  16. */
  17. class WC_Settings_Tax extends WC_Settings_Page {
  18. /**
  19. * Constructor.
  20. */
  21. public function __construct() {
  22. $this->id = 'tax';
  23. $this->label = __( 'Tax', 'woocommerce' );
  24. add_filter( 'woocommerce_settings_tabs_array', array( $this, 'add_settings_page' ), 20 );
  25. if ( wc_tax_enabled() ) {
  26. add_action( 'woocommerce_sections_' . $this->id, array( $this, 'output_sections' ) );
  27. add_action( 'woocommerce_settings_' . $this->id, array( $this, 'output' ) );
  28. add_action( 'woocommerce_settings_save_' . $this->id, array( $this, 'save' ) );
  29. }
  30. }
  31. /**
  32. * Add this page to settings.
  33. *
  34. * @param array $pages Existing pages.
  35. * @return array|mixed
  36. */
  37. public function add_settings_page( $pages ) {
  38. if ( wc_tax_enabled() ) {
  39. return parent::add_settings_page( $pages );
  40. } else {
  41. return $pages;
  42. }
  43. }
  44. /**
  45. * Get own sections.
  46. *
  47. * @return array
  48. */
  49. protected function get_own_sections() {
  50. $sections = array(
  51. '' => __( 'Tax options', 'woocommerce' ),
  52. 'standard' => __( 'Standard rates', 'woocommerce' ),
  53. );
  54. // Get tax classes and display as links.
  55. $tax_classes = WC_Tax::get_tax_classes();
  56. foreach ( $tax_classes as $class ) {
  57. /* translators: $s tax rate section name */
  58. $sections[ sanitize_title( $class ) ] = sprintf( __( '%s rates', 'woocommerce' ), $class );
  59. }
  60. return $sections;
  61. }
  62. /**
  63. * Get settings array.
  64. *
  65. * @return array
  66. */
  67. public function get_settings_for_default_section() {
  68. return include __DIR__ . '/views/settings-tax.php';
  69. }
  70. /**
  71. * Output the settings.
  72. */
  73. public function output() {
  74. global $current_section;
  75. $tax_classes = WC_Tax::get_tax_class_slugs();
  76. if ( 'standard' === $current_section || in_array( $current_section, array_filter( $tax_classes ), true ) ) {
  77. $this->output_tax_rates();
  78. } else {
  79. parent::output();
  80. }
  81. }
  82. /**
  83. * Save settings.
  84. */
  85. public function save() {
  86. // phpcs:disable WordPress.Security.NonceVerification.Missing
  87. global $current_section;
  88. if ( ! $current_section ) {
  89. $this->save_settings_for_current_section();
  90. if ( isset( $_POST['woocommerce_tax_classes'] ) ) {
  91. $this->save_tax_classes( wp_unslash( $_POST['woocommerce_tax_classes'] ) ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
  92. }
  93. } elseif ( ! empty( $_POST['tax_rate_country'] ) ) {
  94. $this->save_tax_rates();
  95. } else {
  96. $this->save_settings_for_current_section();
  97. }
  98. $this->do_update_options_action();
  99. // Invalidate caches.
  100. WC_Cache_Helper::invalidate_cache_group( 'taxes' );
  101. WC_Cache_Helper::get_transient_version( 'shipping', true );
  102. // phpcs:enable WordPress.Security.NonceVerification.Missing
  103. }
  104. /**
  105. * Saves tax classes defined in the textarea to the tax class table instead of an option.
  106. *
  107. * @param string $raw_tax_classes Posted value.
  108. * @return null
  109. */
  110. public function save_tax_classes( $raw_tax_classes ) {
  111. $tax_classes = array_filter( array_map( 'trim', explode( "\n", $raw_tax_classes ) ) );
  112. $existing_tax_classes = WC_Tax::get_tax_classes();
  113. $removed = array_diff( $existing_tax_classes, $tax_classes );
  114. $added = array_diff( $tax_classes, $existing_tax_classes );
  115. foreach ( $removed as $name ) {
  116. WC_Tax::delete_tax_class_by( 'name', $name );
  117. }
  118. foreach ( $added as $name ) {
  119. $tax_class = WC_Tax::create_tax_class( $name );
  120. // Display any error that could be triggered while creating tax classes.
  121. if ( is_wp_error( $tax_class ) ) {
  122. WC_Admin_Settings::add_error(
  123. sprintf(
  124. /* translators: 1: tax class name 2: error message */
  125. esc_html__( 'Additional tax class "%1$s" couldn\'t be saved. %2$s.', 'woocommerce' ),
  126. esc_html( $name ),
  127. $tax_class->get_error_message()
  128. )
  129. );
  130. }
  131. }
  132. return null;
  133. }
  134. /**
  135. * Output tax rate tables.
  136. */
  137. public function output_tax_rates() {
  138. global $current_section;
  139. $current_class = $this->get_current_tax_class();
  140. $countries = array();
  141. foreach ( WC()->countries->get_allowed_countries() as $value => $label ) {
  142. $countries[] = array(
  143. 'value' => $value,
  144. 'label' => esc_js( html_entity_decode( $label ) ),
  145. );
  146. }
  147. $states = array();
  148. foreach ( WC()->countries->get_allowed_country_states() as $label ) {
  149. foreach ( $label as $code => $state ) {
  150. $states[] = array(
  151. 'value' => $code,
  152. 'label' => esc_js( html_entity_decode( $state ) ),
  153. );
  154. }
  155. }
  156. $base_url = admin_url(
  157. add_query_arg(
  158. array(
  159. 'page' => 'wc-settings',
  160. 'tab' => 'tax',
  161. 'section' => $current_section,
  162. ),
  163. 'admin.php'
  164. )
  165. );
  166. // Localize and enqueue our js.
  167. wp_localize_script(
  168. 'wc-settings-tax',
  169. 'htmlSettingsTaxLocalizeScript',
  170. array(
  171. 'current_class' => $current_class,
  172. 'wc_tax_nonce' => wp_create_nonce( 'wc_tax_nonce-class:' . $current_class ),
  173. 'base_url' => $base_url,
  174. 'rates' => array_values( WC_Tax::get_rates_for_tax_class( $current_class ) ),
  175. 'page' => ! empty( $_GET['p'] ) ? absint( $_GET['p'] ) : 1, // phpcs:ignore WordPress.Security.NonceVerification.Recommended
  176. 'limit' => 100,
  177. 'countries' => $countries,
  178. 'states' => $states,
  179. 'default_rate' => array(
  180. 'tax_rate_id' => 0,
  181. 'tax_rate_country' => '',
  182. 'tax_rate_state' => '',
  183. 'tax_rate' => '',
  184. 'tax_rate_name' => '',
  185. 'tax_rate_priority' => 1,
  186. 'tax_rate_compound' => 0,
  187. 'tax_rate_shipping' => 1,
  188. 'tax_rate_order' => null,
  189. 'tax_rate_class' => $current_class,
  190. ),
  191. 'strings' => array(
  192. 'no_rows_selected' => __( 'No row(s) selected', 'woocommerce' ),
  193. 'unload_confirmation_msg' => __( 'Your changed data will be lost if you leave this page without saving.', 'woocommerce' ),
  194. 'csv_data_cols' => array(
  195. __( 'Country code', 'woocommerce' ),
  196. __( 'State code', 'woocommerce' ),
  197. __( 'Postcode / ZIP', 'woocommerce' ),
  198. __( 'City', 'woocommerce' ),
  199. __( 'Rate %', 'woocommerce' ),
  200. __( 'Tax name', 'woocommerce' ),
  201. __( 'Priority', 'woocommerce' ),
  202. __( 'Compound', 'woocommerce' ),
  203. __( 'Shipping', 'woocommerce' ),
  204. __( 'Tax class', 'woocommerce' ),
  205. ),
  206. ),
  207. )
  208. );
  209. wp_enqueue_script( 'wc-settings-tax' );
  210. include __DIR__ . '/views/html-settings-tax.php';
  211. }
  212. /**
  213. * Get tax class being edited.
  214. *
  215. * @return string
  216. */
  217. private static function get_current_tax_class() {
  218. global $current_section;
  219. $tax_classes = WC_Tax::get_tax_classes();
  220. $current_class = '';
  221. foreach ( $tax_classes as $class ) {
  222. if ( sanitize_title( $class ) === $current_section ) {
  223. $current_class = $class;
  224. }
  225. }
  226. return $current_class;
  227. }
  228. /**
  229. * Get a posted tax rate.
  230. *
  231. * @param string $key Key of tax rate in the post data array.
  232. * @param int $order Position/order of rate.
  233. * @param string $class Tax class for rate.
  234. * @return array
  235. */
  236. private function get_posted_tax_rate( $key, $order, $class ) {
  237. // phpcs:disable WordPress.Security.NonceVerification.Missing -- this is called from 'save_tax_rates' only, where nonce is already verified.
  238. $tax_rate = array();
  239. $tax_rate_keys = array(
  240. 'tax_rate_country',
  241. 'tax_rate_state',
  242. 'tax_rate',
  243. 'tax_rate_name',
  244. 'tax_rate_priority',
  245. );
  246. // phpcs:disable WordPress.Security.NonceVerification.Missing
  247. foreach ( $tax_rate_keys as $tax_rate_key ) {
  248. if ( isset( $_POST[ $tax_rate_key ], $_POST[ $tax_rate_key ][ $key ] ) ) {
  249. $tax_rate[ $tax_rate_key ] = wc_clean( wp_unslash( $_POST[ $tax_rate_key ][ $key ] ) );
  250. }
  251. }
  252. $tax_rate['tax_rate_compound'] = isset( $_POST['tax_rate_compound'][ $key ] ) ? 1 : 0;
  253. $tax_rate['tax_rate_shipping'] = isset( $_POST['tax_rate_shipping'][ $key ] ) ? 1 : 0;
  254. $tax_rate['tax_rate_order'] = $order;
  255. $tax_rate['tax_rate_class'] = $class;
  256. // phpcs:enable WordPress.Security.NonceVerification.Missing
  257. return $tax_rate;
  258. // phpcs:enable WordPress.Security.NonceVerification.Missing
  259. }
  260. /**
  261. * Save tax rates.
  262. */
  263. public function save_tax_rates() {
  264. // phpcs:disable WordPress.Security.NonceVerification.Missing -- this is called via "do_action('woocommerce_settings_save_'...") in base class, where nonce is verified first.
  265. global $wpdb;
  266. $current_class = sanitize_title( $this->get_current_tax_class() );
  267. // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotValidated, WordPress.Security.NonceVerification.Missing
  268. $posted_countries = wc_clean( wp_unslash( $_POST['tax_rate_country'] ) );
  269. // get the tax rate id of the first submited row.
  270. $first_tax_rate_id = key( $posted_countries );
  271. // get the order position of the first tax rate id.
  272. $tax_rate_order = absint( $wpdb->get_var( $wpdb->prepare( "SELECT tax_rate_order FROM {$wpdb->prefix}woocommerce_tax_rates WHERE tax_rate_id = %s", $first_tax_rate_id ) ) );
  273. $index = isset( $tax_rate_order ) ? $tax_rate_order : 0;
  274. // Loop posted fields.
  275. // phpcs:disable WordPress.Security.NonceVerification.Missing
  276. foreach ( $posted_countries as $key => $value ) {
  277. $mode = ( 0 === strpos( $key, 'new-' ) ) ? 'insert' : 'update';
  278. $tax_rate = $this->get_posted_tax_rate( $key, $index ++, $current_class );
  279. if ( 'insert' === $mode ) {
  280. $tax_rate_id = WC_Tax::_insert_tax_rate( $tax_rate );
  281. } elseif ( isset( $_POST['remove_tax_rate'][ $key ] ) && 1 === absint( $_POST['remove_tax_rate'][ $key ] ) ) {
  282. $tax_rate_id = absint( $key );
  283. WC_Tax::_delete_tax_rate( $tax_rate_id );
  284. continue;
  285. } else {
  286. $tax_rate_id = absint( $key );
  287. WC_Tax::_update_tax_rate( $tax_rate_id, $tax_rate );
  288. }
  289. if ( isset( $_POST['tax_rate_postcode'][ $key ] ) ) {
  290. WC_Tax::_update_tax_rate_postcodes( $tax_rate_id, wc_clean( wp_unslash( $_POST['tax_rate_postcode'][ $key ] ) ) );
  291. }
  292. if ( isset( $_POST['tax_rate_city'][ $key ] ) ) {
  293. WC_Tax::_update_tax_rate_cities( $tax_rate_id, wc_clean( wp_unslash( $_POST['tax_rate_city'][ $key ] ) ) );
  294. }
  295. }
  296. // phpcs:enable WordPress.Security.NonceVerification.Missing
  297. }
  298. }
  299. return new WC_Settings_Tax();