PageRenderTime 55ms CodeModel.GetById 19ms RepoModel.GetById 1ms app.codeStats 0ms

/admin/jigoshop-admin-settings-api.php

https://github.com/ThemesWpFr/jigoshop
PHP | 1313 lines | 939 code | 209 blank | 165 comment | 122 complexity | e419b54d27cb973f3f1d6d9d5274a9dc MD5 | raw file
Possible License(s): GPL-3.0
  1. <?php
  2. /**
  3. * Jigoshop_Admin_Settings class for management and display of all Jigoshop option settings
  4. *
  5. * DISCLAIMER
  6. *
  7. * Do not edit or add directly to this file if you wish to upgrade Jigoshop to newer
  8. * versions in the future. If you wish to customise Jigoshop core for your needs,
  9. * please use our GitHub repository to publish essential changes for consideration.
  10. *
  11. * @package Jigoshop
  12. * @category Admin
  13. * @author Jigowatt
  14. * @copyright Copyright (c) 2011-2012 Jigowatt Ltd.
  15. * @license http://jigoshop.com/license/commercial-edition
  16. */
  17. class Jigoshop_Admin_Settings extends Jigoshop_Singleton {
  18. private $our_parser;
  19. /**
  20. * Constructor
  21. *
  22. * @since 1.3
  23. */
  24. protected function __construct() {
  25. $this->our_parser = new Jigoshop_Options_Parser(
  26. self::get_options()->get_default_options(),
  27. JIGOSHOP_OPTIONS
  28. );
  29. add_action( 'current_screen', array( $this, 'register_settings' ) );
  30. }
  31. /**
  32. * Scripts for the Options page
  33. *
  34. * @since 1.3
  35. */
  36. public function settings_scripts() {
  37. // http://jquerytools.org/documentation/rangeinput/index.html
  38. wp_register_script( 'jquery-tools', jigoshop::assets_url() . '/assets/js/jquery.tools.min.js', array( 'jquery' ), '1.2.7' );
  39. wp_enqueue_script( 'jquery-tools' );
  40. wp_register_script( 'jigoshop-bootstrap-tooltip', jigoshop::assets_url() . '/assets/js/bootstrap-tooltip.min.js', array( 'jquery' ), '2.0.3' );
  41. wp_enqueue_script( 'jigoshop-bootstrap-tooltip' );
  42. wp_register_script( 'jigoshop-select2', jigoshop::assets_url() . '/assets/js/select2.min.js', array( 'jquery' ), '3.1' );
  43. wp_enqueue_script( 'jigoshop-select2' );
  44. }
  45. /**
  46. * Styling for the options page
  47. *
  48. * @since 1.3
  49. */
  50. public function settings_styles() {
  51. wp_register_style( 'jigoshop-select2', jigoshop::assets_url() . '/assets/css/select2.css', '', '3.1', 'screen' );
  52. wp_enqueue_style( 'jigoshop-select2' );
  53. do_action( 'jigoshop_settings_styles' ); // user defined stylesheets should be registered and queued
  54. }
  55. /**
  56. * Register settings
  57. *
  58. * @since 1.3
  59. */
  60. public function register_settings() {
  61. // Weed out all admin pages except the Jigoshop Settings page hits
  62. global $pagenow;
  63. if ( $pagenow <> 'admin.php' && $pagenow <> 'options.php' ) return;
  64. $screen = get_current_screen();
  65. if ( $screen->base <> 'jigoshop_page_jigoshop_settings' && $screen->base <> 'options' ) return;
  66. $slug = $this->get_current_tab_slug();
  67. $options = $this->our_parser->tabs[$slug];
  68. if ( ! is_array( $options ) ) {
  69. jigoshop_log( "Jigoshop Settings API: -NO- valid options for 'register_settings()' - EXITING with:" );
  70. jigoshop_log( $options );
  71. return;
  72. }
  73. register_setting( JIGOSHOP_OPTIONS, JIGOSHOP_OPTIONS, array( $this, 'validate_settings' ) );
  74. if ( is_array( $options )) foreach ( $options as $index => $option ) {
  75. switch ( $option['type'] ) {
  76. case 'title':
  77. add_settings_section( $option['section'], $option['name'], array( $this, 'display_section' ), JIGOSHOP_OPTIONS );
  78. break;
  79. default:
  80. $this->create_setting( $index, $option );
  81. break;
  82. }
  83. }
  84. }
  85. /**
  86. * Create a settings field
  87. *
  88. * @since 1.3
  89. */
  90. public function create_setting( $index, $option = array() ) {
  91. $defaults = array(
  92. 'tab' => '',
  93. 'section' => '',
  94. 'id' => null,
  95. 'type' => '',
  96. 'name' => '',
  97. 'desc' => '',
  98. 'tip' => '',
  99. 'std' => '',
  100. 'choices' => array(),
  101. 'class' => '',
  102. 'display' => null,
  103. 'update' => null,
  104. 'extra' => null
  105. );
  106. extract( wp_parse_args( $option, $defaults ) );
  107. $id = ! empty( $id ) ? $id : $section.$index;
  108. $field_args = array(
  109. 'tab' => $tab,
  110. 'section' => $section,
  111. 'id' => $id,
  112. 'type' => $type,
  113. 'name' => $name,
  114. 'desc' => $desc,
  115. 'tip' => $tip,
  116. "std" => $std,
  117. 'choices' => $choices,
  118. 'label_for' => $id,
  119. 'class' => $class,
  120. 'display' => $display,
  121. 'update' => $update,
  122. 'extra' => $extra
  123. );
  124. if ( $type <> 'tab' ) {
  125. add_settings_field(
  126. $id,
  127. ($type == 'checkbox') ? '' : esc_attr( $name ),
  128. array( $this, 'display_option' ),
  129. JIGOSHOP_OPTIONS,
  130. $section,
  131. $field_args
  132. );
  133. }
  134. }
  135. /**
  136. * Format markup for an option and output it
  137. *
  138. * @since 1.3
  139. */
  140. public function display_option( $option ) {
  141. echo $this->our_parser->format_option_for_display( $option );
  142. }
  143. /**
  144. * Description for section
  145. *
  146. * @since 1.3
  147. */
  148. public function display_section( $section ) {
  149. $options = $this->our_parser->these_options;
  150. foreach ( $options as $index => $option ) {
  151. if ( isset( $option['name'] ) && $section['title'] == $option['name'] ) {
  152. if ( ! empty( $option['desc'] )) {
  153. echo '<p class="section_description">' . $option['desc'] . '</p>';
  154. }
  155. }
  156. }
  157. }
  158. /**
  159. * Render the Options page
  160. *
  161. * @since 1.3
  162. */
  163. public function output_markup() {
  164. ?>
  165. <div class="wrap jigoshop">
  166. <div class="icon32 icon32-jigoshop-settings" id="icon-jigoshop"><br></div>
  167. <?php do_action( 'jigoshop_admin_settings_notices' ); ?>
  168. <h2 class="nav-tab-wrapper jigoshop-nav-tab-wrapper">
  169. <?php echo $this->build_tab_menu_items(); ?>
  170. </h2>
  171. <noscript>
  172. <div id="jigoshop-js-warning" class="error"><?php _e( 'Warning- This options panel may not work properly without javascript!', 'jigoshop' ); ?></div>
  173. </noscript>
  174. <?php settings_errors(); ?>
  175. <form action="options.php" id="mainform" method="post">
  176. <div class="jigoshop-settings">
  177. <div id="tabs-wrap">
  178. <?php settings_fields( JIGOSHOP_OPTIONS ); ?>
  179. <?php do_settings_sections( JIGOSHOP_OPTIONS ); ?>
  180. <p class="submit">
  181. <input name="Submit" type="submit" class="button-primary" value="<?php echo sprintf( __( "Save %s Changes", 'jigoshop' ), $this->get_current_tab_name() ); ?>" />
  182. </p>
  183. </div>
  184. </div>
  185. </form>
  186. </div>
  187. <script type="text/javascript">
  188. /*<![CDATA[*/
  189. jQuery(function($) {
  190. // Fade out the status message
  191. jQuery('.updated').delay(2500).fadeOut(1500);
  192. // jQuery Tools range tool
  193. jQuery(":range").rangeinput();
  194. // Countries
  195. jQuery('select#jigoshop_allowed_countries').change(function(){
  196. // hide-show multi_select_countries
  197. if (jQuery(this).val()=="specific") {
  198. jQuery(this).parent().parent().next('tr').show();
  199. } else {
  200. jQuery(this).parent().parent().next('tr').hide();
  201. }
  202. }).change();
  203. // permalink double save hack (do we need this anymore -JAP-)
  204. jQuery.get('<?php echo admin_url('options-permalink.php') ?>');
  205. });
  206. /*]]>*/
  207. </script>
  208. <?php do_action( 'jigoshop_settings_scripts' ); ?>
  209. <?php
  210. }
  211. /**
  212. * Create the Navigation Menu Tabs
  213. *
  214. * @since 1.3
  215. */
  216. function build_tab_menu_items() {
  217. $menus_li = '';
  218. $slug = $this->get_current_tab_slug();
  219. foreach ( $this->our_parser->tab_headers as $tab ) {
  220. $this_slug = sanitize_title( $tab );
  221. if ( $slug == $this_slug ) {
  222. $menus_li .= '<a class="nav-tab nav-tab-active"
  223. title="'.$tab.'"
  224. href="?page=jigoshop_settings&tab='.$this_slug.'">' . $tab . '</a>';
  225. } else {
  226. $menus_li .= '<a class="nav-tab"
  227. title="'.$tab.'"
  228. href="?page=jigoshop_settings&tab='.$this_slug.'">' . $tab . '</a>';
  229. }
  230. }
  231. return $menus_li;
  232. }
  233. /**
  234. * Return the current Tab slug in view
  235. *
  236. * @since 1.3
  237. */
  238. public function get_current_tab_slug() {
  239. $current = "";
  240. if ( isset( $_GET['tab'] ) ) {
  241. $current = $_GET['tab'];
  242. } else if ( isset( $_POST['_wp_http_referer'] ) && strpos($_POST['_wp_http_referer'], '&tab=') !== false ) {
  243. // /site/wp-admin/admin.php?page=jigoshop_settings&tab=products-inventory&settings-updated=true
  244. // find the 'tab'
  245. $result = strstr( $_POST['_wp_http_referer'], '&tab=' );
  246. // &tab=products-inventory&settings-updated=true
  247. $result = substr( $result, 5 );
  248. // products-inventory&settings-updated=true
  249. $end_pos = strpos( $result, '&' );
  250. $current = substr( $result, 0 , $end_pos !== false ? $end_pos : strlen( $result ) );
  251. // products-inventory
  252. } else {
  253. $current = $this->our_parser->these_options[0]['name'];
  254. }
  255. return sanitize_title( $current );
  256. }
  257. /**
  258. * Return the current Tab full name in view
  259. *
  260. * @since 1.3
  261. */
  262. public function get_current_tab_name() {
  263. $current = $this->our_parser->these_options[0]['name'];
  264. $slug = $this->get_current_tab_slug();
  265. foreach ( $this->our_parser->tab_headers as $tab ) {
  266. $this_slug = sanitize_title( $tab );
  267. if ( $slug == $this_slug ) {
  268. $current = $tab;
  269. }
  270. }
  271. return $current;
  272. }
  273. /**
  274. * Validate settings
  275. *
  276. * @since 1.3
  277. */
  278. public function validate_settings( $input ) {
  279. if ( empty( $_POST ) ) {
  280. return $input;
  281. }
  282. $defaults = $this->our_parser->these_options;
  283. $current_options = self::get_options()->get_current_options();
  284. $valid_input = $current_options; // we start with the current options
  285. // Find the current TAB we are working with and use it's option settings
  286. $this_section = $this->get_current_tab_name();
  287. $tab = $this->our_parser->tabs[sanitize_title( $this_section )];
  288. // with each option, get it's type and validate it
  289. if ( ! empty( $tab )) foreach ( $tab as $index => $setting ) {
  290. if ( isset( $setting['id'] ) ) {
  291. // special case tax classes should be updated, they will do nothing if this is not the right TAB
  292. if ( $setting['id'] == 'jigoshop_tax_rates' ) {
  293. $valid_input['jigoshop_tax_rates'] = $this->get_updated_tax_classes();
  294. update_option( $setting['id'], $valid_input['jigoshop_tax_rates'] ); // TODO: remove in v1.5 - provides compatibility
  295. continue;
  296. }
  297. // get this settings options
  298. foreach ( $defaults as $default_index => $option ) {
  299. if ( in_array( $setting['id'], $option ) ) {
  300. break;
  301. }
  302. }
  303. $value = isset( $input[$setting['id']] ) ? $input[$setting['id']] : null ;
  304. // we have a $setting
  305. // $value has the WordPress user submitted value for this $setting
  306. // $option has this $setting parameters
  307. // validate for $option 'type' checking for a submitted $value
  308. switch ( $option['type'] ) {
  309. case 'user_defined' :
  310. if ( isset( $option['update'] ) ) {
  311. if ( is_callable( $option['update'], true ) ) {
  312. $result = call_user_func( $option['update'] );
  313. $valid_input[$setting['id']] = $result;
  314. update_option( $setting['id'], $valid_input[$setting['id']] ); // TODO: remove in v1.5 - provides compatibility
  315. }
  316. }
  317. break;
  318. case 'multi_select_countries' :
  319. if ( isset( $value ) ) {
  320. $countries = jigoshop_countries::$countries;
  321. asort( $countries );
  322. $selected = array();
  323. foreach ( $countries as $key => $val ) {
  324. if ( in_array( $key, (array)$value ) ) {
  325. $selected[] = $key;
  326. }
  327. }
  328. $valid_input[$setting['id']] = $selected;
  329. update_option( $setting['id'], $valid_input[$setting['id']] ); // TODO: remove in v1.5 - provides compatibility
  330. }
  331. break;
  332. case 'checkbox' :
  333. // there will be no $value for a false checkbox, set it now
  334. $valid_input[$setting['id']] = isset( $value ) ? 'yes' : 'no';
  335. update_option( $setting['id'], $valid_input[$setting['id']] ); // TODO: remove in v1.5 - provides compatibility
  336. break;
  337. case 'multicheck' :
  338. $selected = array();
  339. foreach ( $option['choices'] as $key => $val ) {
  340. if ( isset( $value[$key] ) ) {
  341. $selected[$key] = true;
  342. } else {
  343. $selected[$key] = false;
  344. }
  345. }
  346. $valid_input[$setting['id']] = $selected;
  347. update_option( $setting['id'], $valid_input[$setting['id']] ); // TODO: remove in v1.5 - provides compatibility
  348. break;
  349. case 'text' :
  350. case 'longtext' :
  351. case 'textarea' :
  352. $valid_input[$setting['id']] = esc_attr( jigowatt_clean( $value ) );
  353. update_option( $setting['id'], $valid_input[$setting['id']] ); // TODO: remove in v1.5 - provides compatibility
  354. break;
  355. case 'email' :
  356. $email = sanitize_email( $value );
  357. if ( $email <> $value ) {
  358. add_settings_error(
  359. $setting['id'],
  360. 'jigoshop_email_error',
  361. sprintf(__('You entered "%s" as the value for "%s" and it was not a valid email address. It was not saved and the original is still in use.','jigoshop'), $value, $setting['name']),
  362. 'error'
  363. );
  364. $valid_input[$setting['id']] = $current_options[$setting['id']];
  365. } else {
  366. $valid_input[$setting['id']] = esc_attr( jigowatt_clean( $email ) );
  367. }
  368. update_option( $setting['id'], $valid_input[$setting['id']] ); // TODO: remove in v1.5 - provides compatibility
  369. break;
  370. case 'decimal' :
  371. $cleaned = jigowatt_clean( $value );
  372. if ( ! jigoshop_validation::is_decimal( $cleaned ) && $cleaned <> '' ) {
  373. add_settings_error(
  374. $setting['id'],
  375. 'jigoshop_decimal_error',
  376. sprintf(__('You entered "%s" as the value for "%s" in "%s" and it was not a valid decimal number (may have leading negative sign, with optional decimal point, numbers 0-9). It was not saved and the original is still in use.','jigoshop'), $value, $setting['name'], $setting['section'] ),
  377. 'error'
  378. );
  379. $valid_input[$setting['id']] = $current_options[$setting['id']];
  380. } else {
  381. $valid_input[$setting['id']] = $cleaned;
  382. }
  383. update_option( $setting['id'], $valid_input[$setting['id']] ); // TODO: remove in v1.5 - provides compatibility
  384. break;
  385. case 'integer' :
  386. $cleaned = jigowatt_clean( $value );
  387. if ( ! jigoshop_validation::is_integer( $cleaned ) && $cleaned <> '' ) {
  388. add_settings_error(
  389. $setting['id'],
  390. 'jigoshop_integer_error',
  391. sprintf(__('You entered "%s" as the value for "%s" in "%s" and it was not a valid integer number (may have leading negative sign, numbers 0-9). It was not saved and the original is still in use.','jigoshop'), $value, $setting['name'], $setting['section'] ),
  392. 'error'
  393. );
  394. $valid_input[$setting['id']] = $current_options[$setting['id']];
  395. } else {
  396. $valid_input[$setting['id']] = $cleaned;
  397. }
  398. update_option( $setting['id'], $valid_input[$setting['id']] ); // TODO: remove in v1.5 - provides compatibility
  399. break;
  400. case 'natural' :
  401. $cleaned = jigowatt_clean( $value );
  402. if ( ! jigoshop_validation::is_natural( $cleaned ) && $cleaned <> '' ) {
  403. add_settings_error(
  404. $setting['id'],
  405. 'jigoshop_natural_error',
  406. sprintf(__('You entered "%s" as the value for "%s" in "%s" and it was not a valid natural number (numbers 0-9). It was not saved and the original is still in use.','jigoshop'), $value, $setting['name'], $setting['section'] ),
  407. 'error'
  408. );
  409. $valid_input[$setting['id']] = $current_options[$setting['id']];
  410. } else {
  411. $valid_input[$setting['id']] = $cleaned;
  412. }
  413. update_option( $setting['id'], $valid_input[$setting['id']] ); // TODO: remove in v1.5 - provides compatibility
  414. break;
  415. default :
  416. if ( isset( $value ) ) {
  417. $valid_input[$setting['id']] = $value;
  418. update_option( $setting['id'], $valid_input[$setting['id']] ); // TODO: remove in v1.5 - provides compatibility
  419. }
  420. break;
  421. }
  422. }
  423. }
  424. // remove all jigoshop_update_options actions on shipping classes when not on the shipping tab
  425. if ( $this_section != __('Shipping','jigoshop') ) {
  426. $this->remove_update_options( jigoshop_shipping::get_all_methods() );
  427. }
  428. if ( $this_section != __('Payment Gateways','jigoshop') ) {
  429. $this->remove_update_options( jigoshop_payment_gateways::payment_gateways() );
  430. }
  431. // Allow any hooked in option updating
  432. do_action( 'jigoshop_update_options' );
  433. $errors = get_settings_errors();
  434. if ( empty( $errors ) ) {
  435. add_settings_error(
  436. '',
  437. 'settings_updated',
  438. sprintf(__('"%s" settings were updated successfully.','jigoshop'), $this_section ),
  439. 'updated'
  440. );
  441. }
  442. return $valid_input; // send it back to WordPress for saving
  443. }
  444. /**
  445. * Remove all jigoshop_update_options actions on shipping and payment classes when not on those tabs
  446. *
  447. * @since 1.3
  448. */
  449. private function remove_update_options( $classes ) {
  450. if ( empty( $classes )) return;
  451. foreach ( $classes as $class ) :
  452. remove_action( 'jigoshop_update_options', array( $class, 'process_admin_options' ));
  453. endforeach;
  454. }
  455. /**
  456. * Defines a custom sort for the tax_rates array. The sort that is needed is that the array is sorted
  457. * by country, followed by state, followed by compound tax. The difference is that compound must be sorted based
  458. * on compound = no before compound = yes. Ultimately, the purpose of the sort is to make sure that country, state
  459. * are all consecutive in the array, and that within those groups, compound = 'yes' always appears last. This is
  460. * so that tax classes that are compounded will be executed last in comparison to those that aren't.
  461. * last.
  462. * <br>
  463. * <pre>
  464. * eg. country = 'CA', state = 'QC', compound = 'yes'<br>
  465. * country = 'CA', state = 'QC', compound = 'no'<br>
  466. *
  467. * will be sorted to have <br>
  468. * country = 'CA', state = 'QC', compound = 'no'<br>
  469. * country = 'CA', state = 'QC', compound = 'yes' <br>
  470. * </pre>
  471. *
  472. * @param type $a the first object to compare with (our inner array)
  473. * @param type $b the second object to compare with (our inner array)
  474. * @return int the results of strcmp
  475. */
  476. function csort_tax_rates($a, $b) {
  477. $str1 = '';
  478. $str2 = '';
  479. $str1 .= $a['country'] . $a['state'] . ($a['compound'] == 'no' ? 'a' : 'b');
  480. $str2 .= $b['country'] . $b['state'] . ($b['compound'] == 'no' ? 'a' : 'b');
  481. return strcmp($str1, $str2);
  482. }
  483. /**
  484. * When Options are saved, return the 'jigoshop_tax_rates' option values
  485. *
  486. * @return mixed false if not rax rates, array of tax rates otherwise
  487. *
  488. * @since 1.3
  489. */
  490. function get_updated_tax_classes() {
  491. $taxFields = array(
  492. 'tax_classes' => '',
  493. 'tax_country' => '',
  494. 'tax_rate' => '',
  495. 'tax_label' => '',
  496. 'tax_shipping'=> '',
  497. 'tax_compound'=> ''
  498. );
  499. $tax_rates = array();
  500. /* Save each array key to a variable */
  501. foreach ( $taxFields as $name => $val )
  502. if ( isset( $_POST[$name] )) $taxFields[$name] = $_POST[$name];
  503. extract( $taxFields );
  504. for ( $i = 0; $i < sizeof( $tax_classes); $i++ ) :
  505. if ( empty( $tax_rate[$i] )) continue;
  506. $countries = $tax_country[$i];
  507. $label = trim($tax_label[$i]);
  508. $rate = number_format((float)jigowatt_clean($tax_rate[$i]), 4);
  509. $class = jigowatt_clean($tax_classes[$i]);
  510. /* Checkboxes */
  511. $shipping = !empty($tax_shipping[$i]) ? 'yes' : 'no';
  512. $compound = !empty($tax_compound[$i]) ? 'yes' : 'no';
  513. /* Save the state & country separately from options eg US:OH */
  514. $states = array();
  515. foreach ( $countries as $k => $countryCode ) :
  516. if ( strstr($countryCode, ':')) :
  517. $cr = explode(':', $countryCode);
  518. $states[$cr[1]] = $cr[0];
  519. unset($countries[$k]);
  520. endif;
  521. endforeach;
  522. /* Save individual state taxes, eg OH => US (State => Country) */
  523. foreach ( $states as $state => $country ) :
  524. $tax_rates[] = array(
  525. 'country' => $country,
  526. 'label' => $label,
  527. 'state' => $state,
  528. 'rate' => $rate,
  529. 'shipping' => $shipping,
  530. 'class' => $class,
  531. 'compound' => $compound,
  532. 'is_all_states'=> false //determines if admin panel should show 'all_states'
  533. );
  534. endforeach;
  535. foreach ( $countries as $country ) :
  536. /* Countries with states */
  537. if ( jigoshop_countries::country_has_states( $country )) {
  538. foreach ( array_keys( jigoshop_countries::$states[$country] ) as $state ) :
  539. $tax_rates[] = array(
  540. 'country' => $country,
  541. 'label' => $label,
  542. 'state' => $state,
  543. 'rate' => $rate,
  544. 'shipping' => $shipping,
  545. 'class' => $class,
  546. 'compound' => $compound,
  547. 'is_all_states'=> true
  548. );
  549. endforeach;
  550. } else { /* This country has no states, eg AF */
  551. $tax_rates[] = array(
  552. 'country' => $country,
  553. 'label' => $label,
  554. 'state' => '*',
  555. 'rate' => $rate,
  556. 'shipping' => $shipping,
  557. 'class' => $class,
  558. 'compound' => $compound,
  559. 'is_all_states'=> false
  560. );
  561. }
  562. endforeach;
  563. endfor;
  564. usort( $tax_rates, array( $this, 'csort_tax_rates' ) );
  565. return $tax_rates;
  566. }
  567. }
  568. /**
  569. * Options Parser Class
  570. *
  571. * Used by the Jigoshop_Admin_Settings class to parse the Jigoshop_Options into sections
  572. * Provides formatted output for display of all Option types
  573. *
  574. * @since 1.3
  575. */
  576. class Jigoshop_Options_Parser {
  577. var $these_options; // The array of default options items to parse
  578. var $tab_headers;
  579. var $tabs;
  580. var $sections;
  581. function __construct( $option_items, $this_options_entry ) {
  582. $this->these_options = $option_items;
  583. $this->parse_options();
  584. }
  585. private function parse_options() {
  586. $tab_headers = array();
  587. $tabs = array();
  588. $sections = array();
  589. foreach ( $this->these_options as $item ) {
  590. $defaults = array(
  591. 'tab' => '',
  592. 'section' => '',
  593. 'id' => null,
  594. 'type' => '',
  595. 'name' => '',
  596. 'desc' => '',
  597. 'tip' => '',
  598. 'std' => '',
  599. 'choices' => array(),
  600. 'class' => '',
  601. 'display' => null,
  602. 'update' => null,
  603. 'extra' => null
  604. );
  605. $item = wp_parse_args( $item, $defaults );
  606. if ( isset( $item['id'] ) ) $item['id'] = sanitize_title( $item['id'] );
  607. if ( $item['type'] == 'tab' ) {
  608. $tab_name = sanitize_title( $item['name'] );
  609. $tab_headers[$tab_name] = $item['name']; // used by get_current_tab_name()
  610. continue;
  611. }
  612. if ( $item['type'] == 'title' ) {
  613. $section_name = sanitize_title( $item['name'] );
  614. }
  615. $item['tab'] = $tab_name;
  616. $item['section'] = isset( $section_name ) ? $section_name : $tab_name;
  617. $tabs[$tab_name][] = $item;
  618. $sections[$item['section']][] = $item;
  619. }
  620. $this->tab_headers = $tab_headers;
  621. $this->tabs = $tabs;
  622. $this->sections = $sections;
  623. }
  624. public function format_option_for_display( $item ) {
  625. $data = Jigoshop_Base::get_options()->get_current_options();
  626. if ( ! isset( $item['id'] )) return ''; // ensure we have an id to work with
  627. $display = ""; // each item builds it's output into this and it's returned for echoing
  628. $class = "";
  629. if ( isset( $item['class'] ) ) {
  630. $class = $item['class'];
  631. }
  632. // display a tooltip if there is one in it's own table data element before the item to display
  633. $display .= '<td class="jigoshop-tooltips">';
  634. if ( ! empty( $item['tip'] )) {
  635. $display .= '<a href="#" tip="'.esc_attr( $item['tip'] ).'" class="tips" tabindex="99"></a>';
  636. }
  637. $display .= '</td>';
  638. $display .= '<td class="forminp">';
  639. // work off the option type and format output for display for each type
  640. switch ( $item['type'] ) {
  641. case 'user_defined':
  642. if ( isset( $item['display'] ) ) {
  643. if ( is_callable( $item['display'], true ) ) {
  644. $display .= call_user_func( $item['display'] );
  645. }
  646. }
  647. break;
  648. case 'gateway_options':
  649. foreach ( jigoshop_payment_gateways::payment_gateways() as $gateway ) :
  650. $gateway->admin_options();
  651. endforeach;
  652. break;
  653. case 'shipping_options':
  654. foreach ( jigoshop_shipping::get_all_methods() as $shipping_method ) :
  655. $shipping_method->admin_options();
  656. endforeach;
  657. break;
  658. case 'tax_rates':
  659. $display .= $this->format_tax_rates_for_display( $item );
  660. break;
  661. /* case 'image_size' : // may not use this, needs work, unhooking (-JAP-)
  662. $width = $data[$item['id']];
  663. $display .= '<input
  664. name="'.JIGOSHOP_OPTIONS.'['.$item['id'].']"
  665. id="'.JIGOSHOP_OPTIONS.'['.$item['id'].']"
  666. class="jigoshop-input jigoshop-text"
  667. type="text"
  668. value="'.esc_attr( $data[$item['id']] ).'" />';
  669. break;
  670. */
  671. case 'single_select_page':
  672. $page_setting = (int) $data[$item['id']];
  673. $args = array(
  674. 'name' => JIGOSHOP_OPTIONS . '[' . $item['id'] . ']',
  675. 'id' => $item['id'],
  676. 'sort_order' => 'ASC',
  677. 'echo' => 0,
  678. 'selected' => $page_setting
  679. );
  680. if ( isset( $item['extra'] )) $args = wp_parse_args( $item['extra'], $args );
  681. $display .= wp_dropdown_pages( $args );
  682. $parts = explode( '<select', $display );
  683. $id = $item['id'];
  684. $display = $parts[0] . '<select id="'.$id.'" class="'.$class.'"' . $parts[1];
  685. ?>
  686. <script type="text/javascript">
  687. jQuery(function() {
  688. jQuery("#<?php echo $id; ?>").select2({ width: '250px' });
  689. });
  690. </script>
  691. <?php
  692. break;
  693. case 'single_select_country':
  694. $countries = jigoshop_countries::$countries;
  695. $country_setting = (string) $data[$item['id']];
  696. if ( strstr( $country_setting, ':' )) :
  697. $country = current( explode( ':', $country_setting) );
  698. $state = end( explode( ':', $country_setting) );
  699. else :
  700. $country = $country_setting;
  701. $state = '*';
  702. endif;
  703. $id = $item['id'];
  704. $display .= '<select id="'.$id.'" class="single_select_country '.$class.'" name="' . JIGOSHOP_OPTIONS . '[' . $item['id'] . ']">';
  705. $display .= jigoshop_countries::country_dropdown_options($country, $state, true, false, false);
  706. $display .= '</select>';
  707. ?>
  708. <script type="text/javascript">
  709. jQuery(function() {
  710. jQuery("#<?php echo $id; ?>").select2({ width: '500px' });
  711. });
  712. </script>
  713. <?php
  714. break;
  715. case 'multi_select_countries':
  716. $countries = jigoshop_countries::$countries;
  717. asort( $countries );
  718. $selections = (array) $data[$item['id']];
  719. $display .= '<select multiple="multiple"
  720. id="'.$item['id'].'"
  721. class="jigoshop-input jigoshop-select '.$class.'"
  722. name="'.JIGOSHOP_OPTIONS.'['.$item['id'].'][]" >';
  723. foreach ( $countries as $key => $val ) {
  724. $display .= '<option value="'.esc_attr( $key ).'" '.(in_array( $key, $selections ) ? 'selected="selected"' : '').' />'.$val.'</option>';
  725. }
  726. $display .= '</select>';
  727. $id = $item['id'];
  728. ?>
  729. <script type="text/javascript">
  730. jQuery(function() {
  731. jQuery("#<?php echo $id; ?>").select2({ width: '500px' });
  732. });
  733. </script>
  734. <?php
  735. break;
  736. case 'button':
  737. if ( isset( $item['extra'] ) )
  738. $display .= '<a id="'.$item['id'].'"
  739. class="button '.$class.'"
  740. href="'. esc_attr( $item['extra'] ) .'"
  741. >'. esc_attr( $item['desc'] ) .'</a>';
  742. $item['desc'] = ''; // temporarily remove it so it doesn't display twice
  743. break;
  744. case 'decimal': // decimal numbers are positive or negative 0-9 inclusive, may include decimal
  745. $display .= '<input
  746. id="'.$item['id'].'"
  747. class="jigoshop-input jigoshop-text '.$class.'"
  748. name="'.JIGOSHOP_OPTIONS.'['.$item['id'].']"
  749. type="number"
  750. step="any"
  751. size="20"
  752. value="'. esc_attr( $data[$item['id']] ).'" />';
  753. break;
  754. case 'integer': // integer numbers are positive or negative 0-9 inclusive
  755. case 'natural': // natural numbers are positive 0-9 inclusive
  756. $display .= '<input
  757. id="'.$item['id'].'"
  758. class="jigoshop-input jigoshop-text '.$class.'"
  759. name="'.JIGOSHOP_OPTIONS.'['.$item['id'].']"
  760. type="number"
  761. size="20"
  762. value="'. esc_attr( $data[$item['id']] ).'" />';
  763. break;
  764. case 'text': // any character sequence
  765. $display .= '<input
  766. id="'.$item['id'].'"
  767. class="jigoshop-input jigoshop-text '.$class.'"
  768. name="'.JIGOSHOP_OPTIONS.'['.$item['id'].']"
  769. type="text"
  770. size="20"
  771. value="'. esc_attr( $data[$item['id']] ).'" />';
  772. break;
  773. case 'midtext':
  774. $display .= '<input
  775. id="'.$item['id'].'"
  776. class="jigoshop-input jigoshop-text '.$class.'"
  777. name="'.JIGOSHOP_OPTIONS.'['.$item['id'].']"
  778. type="text"
  779. size="40"
  780. value="'. esc_attr( $data[$item['id']] ).'" />';
  781. break;
  782. case 'longtext':
  783. $display .= '<input
  784. id="'.$item['id'].'"
  785. class="jigoshop-input jigoshop-text '.$class.'"
  786. name="'.JIGOSHOP_OPTIONS.'['.$item['id'].']"
  787. type="text"
  788. size="80"
  789. value="'. esc_attr( $data[$item['id']] ).'" />';
  790. break;
  791. case 'email':
  792. $display .= '<input
  793. id="'.$item['id'].'"
  794. class="jigoshop-input jigoshop-text jigoshop-email '.$class.'"
  795. name="'.JIGOSHOP_OPTIONS.'['.$item['id'].']"
  796. type="text"
  797. size="40"
  798. value="'. esc_attr( $data[$item['id']] ).'" />';
  799. break;
  800. case 'textarea':
  801. $cols = '60';
  802. $ta_value = '';
  803. if ( isset( $item['choices'] ) ) {
  804. $ta_options = $item['choices'];
  805. if ( isset( $ta_options['cols'] ) ) {
  806. $cols = $ta_options['cols'];
  807. }
  808. }
  809. $ta_value = stripslashes( $data[$item['id']] );
  810. $display .= '<textarea
  811. id="'.$item['id'].'"
  812. class="jigoshop-input jigoshop-textarea '.$class.'"
  813. name="'.JIGOSHOP_OPTIONS.'['.$item['id'].']"
  814. cols="'.$cols.'"
  815. rows="4">'.esc_textarea( $ta_value ).'</textarea>';
  816. break;
  817. case "radio":
  818. // default to horizontal display of choices ( 'horizontal' may or may not be defined )
  819. if ( ! isset( $item['extra'] ) || ! in_array( 'vertical', $item['extra'] ) ) {
  820. $display .= '<div class="jigoshop-radio-horz">';
  821. foreach ( $item['choices'] as $option => $name ) {
  822. $display .= '<input
  823. class="jigoshop-input jigoshop-radio '.$class.'"
  824. name="'.JIGOSHOP_OPTIONS.'['.$item['id'].']"
  825. id="' . $item['id'] . '[' . $option . ']"
  826. type="radio"
  827. value="'.$option.'" '.checked( $data[$item['id']], $option, false ).' /><label for="' . $item['id'] . '[' . $option . ']">'.$name.'</label>';
  828. }
  829. $display .= '</div>';
  830. } else if ( isset( $item['extra'] ) && in_array( 'vertical', $item['extra'] ) ) {
  831. $display .= '<ul class="jigoshop-radio-vert">';
  832. foreach ( $item['choices'] as $option => $name ) {
  833. $display .= '<li><input
  834. class="jigoshop-input jigoshop-radio '.$class.'"
  835. name="'.JIGOSHOP_OPTIONS.'['.$item['id'].']"
  836. id="' . $item['id'] . '[' . $option . ']"
  837. type="radio"
  838. value="'.$option.'" '.checked( $data[$item['id']], $option, false ).' /><label for="' . $item['id'] . '[' . $option . ']">'.$name.'</label></li>';
  839. }
  840. $display .= '</ul>';
  841. }
  842. break;
  843. case 'checkbox':
  844. $display .= '<span class="jigoshop-container"><input
  845. id="'.$item['id'].'"
  846. type="checkbox"
  847. class="jigoshop-input jigoshop-checkbox '.$class.'"
  848. name="'.JIGOSHOP_OPTIONS.'['.$item['id'].']"
  849. '.checked($data[$item['id']], 'yes', false).' />
  850. <label for="'.$item['id'].'">'.$item['name'].'</label></span>';
  851. break;
  852. case 'multicheck':
  853. $multi_stored = $data[$item['id']];
  854. // default to horizontal display of choices ( 'horizontal' may or may not be defined )
  855. if ( ! isset( $item['extra'] ) || ! in_array( 'vertical', $item['extra'] ) ) {
  856. $display .= '<div class="jigoshop-multi-checkbox-horz '.$class.'">';
  857. foreach ( $item['choices'] as $key => $option ) {
  858. $display .= '<input
  859. id="'.$item['id'].'_'.$key.'"
  860. class="jigoshop-input"
  861. name="'.JIGOSHOP_OPTIONS.'['.$item['id'].']['.$key.']"
  862. type="checkbox"
  863. '.checked( $multi_stored[$key], true, false ).' />
  864. <label for="'.$item['id'].'_'.$key.'">'.$option.'</label>';
  865. }
  866. $display .= '</div>';
  867. } else if ( isset( $item['extra'] ) && in_array( 'vertical', $item['extra'] ) ) {
  868. $display .= '<ul class="jigoshop-multi-checkbox-vert '.$class.'">';
  869. foreach ( $item['choices'] as $key => $option ) {
  870. $display .= '<li><input
  871. id="'.$item['id'].'_'.$key.'"
  872. class="jigoshop-input"
  873. name="'.JIGOSHOP_OPTIONS.'['.$item['id'].']['.$key.']"
  874. type="checkbox"
  875. '.checked( $multi_stored[$key], true, false ).' />
  876. <label for="'.$item['id'].'_'.$key.'">'.$option.'</label></li>';
  877. }
  878. $display .= '</ul>';
  879. }
  880. break;
  881. case 'range':
  882. $display .= '<input
  883. id="'.$item['id'].'"
  884. class="jigoshop-input jigoshop-range '.$class.'"
  885. name="'.JIGOSHOP_OPTIONS.'['.$item['id'].']"
  886. type="range"
  887. min="'.$item['extra']['min'].'"
  888. max="'.$item['extra']['max'].'"
  889. step="'.$item['extra']['step'].'"
  890. value="'.$data[$item['id']].'" />';
  891. break;
  892. case 'select':
  893. $display .= '<select
  894. id="'.$item['id'].'"
  895. class="jigoshop-input jigoshop-select '.$class.'"
  896. name="'.JIGOSHOP_OPTIONS.'['.$item['id'].']" >';
  897. foreach ( $item['choices'] as $value => $label ) {
  898. if ( is_array( $label )) {
  899. $display .= '<optgroup label="'.$value.'">';
  900. foreach ( $label as $subValue => $subLabel ) {
  901. $display .= '<option
  902. value="'.esc_attr( $subValue ).'" '.selected( $data[$item['id']], $subValue, false ).' />'.$subLabel.'
  903. </option>';
  904. }
  905. $display .= '</optgroup>';
  906. }
  907. else {
  908. $display .= '<option
  909. value="'.esc_attr( $value ).'" '.selected( $data[$item['id']], $value, false ).' />'.$label.'
  910. </option>';
  911. }
  912. }
  913. $display .= '</select>';
  914. $id = $item['id'];
  915. ?>
  916. <script type="text/javascript">
  917. jQuery(function() {
  918. jQuery("#<?php echo $id; ?>").select2({ width: '250px' });
  919. });
  920. </script>
  921. <?php
  922. break;
  923. default:
  924. jigoshop_log( "UNKOWN _type_ in Options parsing" );
  925. jigoshop_log( $item );
  926. }
  927. if ( $item['type'] != 'tab' ) {
  928. if ( empty( $item['desc'] ) ) {
  929. $explain_value = '';
  930. } else {
  931. $explain_value = $item['desc'];
  932. }
  933. $display .= '<div class="jigoshop-explain"><small>' . $explain_value . '</small></div>';
  934. $display .= '</td>';
  935. }
  936. return $display;
  937. }
  938. function array_find( $needle, $haystack ) {
  939. foreach ( $haystack as $key => $val ):
  940. if ( $needle == array( "label" => $val['label'], "compound" => $val['compound'], 'rate' => $val['rate'], 'shipping' => $val['shipping'], 'class' => $val['class'] ) ):
  941. return $key;
  942. endif;
  943. endforeach;
  944. return false;
  945. }
  946. function array_compare( $tax_rates ) {
  947. $after = array();
  948. foreach ( $tax_rates as $key => $val ):
  949. $first_two = array("label" => $val['label'], "compound" => $val['compound'], 'rate' => $val['rate'], 'shipping' => $val['shipping'], 'class' => $val['class'] );
  950. $found = $this->array_find( $first_two, $after );
  951. if ( $found !== false ):
  952. $combined = $after[$found]["state"];
  953. $combined2 = $after[$found]["country"];
  954. $combined = !is_array($combined) ? array($combined) : $combined;
  955. $combined2 = !is_array($combined2) ? array($combined2) : $combined2;
  956. $after[$found] = array_merge($first_two,array( "state" => array_merge($combined,array($val['state'])), "country" => array_merge($combined2,array($val['country'])) ));
  957. else:
  958. $after = array_merge($after,array(array_merge($first_two,array("state" => $val['state'], "country" => $val['country']))));
  959. endif;
  960. endforeach;
  961. return $after;
  962. }
  963. /*
  964. * Format tax rates array for display
  965. */
  966. function format_tax_rates_for_display( $value ) {
  967. $_tax = new jigoshop_tax();
  968. $tax_classes = $_tax->get_tax_classes();
  969. $tax_rates = (array) Jigoshop_Base::get_options()->get_option( 'jigoshop_tax_rates' );
  970. $applied_all_states = array();
  971. ob_start();
  972. ?>
  973. <div id="jigoshop_tax_rates">
  974. <table class="tax_rate_rules" cellspacing="0">
  975. <thead>
  976. <tr>
  977. <th><?php _e('Remove', 'jigoshop'); ?></th>
  978. <th><?php _e('Tax Classes', 'jigoshop'); ?></th>
  979. <th><?php _e('Online Label', 'jigoshop'); ?></th>
  980. <th><?php _e('Country/State', 'jigoshop'); ?></th>
  981. <th><?php _e("Rate (%)", 'jigoshop'); ?></th>
  982. <th><?php _e('Apply to shipping', 'jigoshop'); ?></th>
  983. <th><?php _e('Compound', 'jigoshop'); ?></th>
  984. </tr>
  985. </thead>
  986. <tfoot>
  987. <tr>
  988. <th><?php _e('Remove', 'jigoshop'); ?></th>
  989. <th><?php _e('Tax Classes', 'jigoshop'); ?></th>
  990. <th><?php _e('Online Label', 'jigoshop'); ?></th>
  991. <th><?php _e('Country/State', 'jigoshop'); ?></th>
  992. <th><?php _e("Rate (%)", 'jigoshop'); ?></th>
  993. <th><?php _e('Apply to shipping', 'jigoshop'); ?></th>
  994. <th><?php _e('Compound', 'jigoshop'); ?></th>
  995. </tr>
  996. </tfoot>
  997. <tbody>
  998. <?php
  999. $i = -1;
  1000. if ( $tax_rates && is_array( $tax_rates ) && sizeof( $tax_rates ) > 0 ) :
  1001. $tax_rates = $this->array_compare( $tax_rates );
  1002. foreach ( $tax_rates as $rate ) :
  1003. if ( isset($rate['is_all_states']) && in_array($tax_rate['country'].$tax_rate['class'], $applied_all_states) )
  1004. continue;
  1005. $i++;// increment counter after check for all states having been applied
  1006. echo '<tr class="tax_rate"><td><a href="#" class="remove button">&times;</a></td>';
  1007. echo '<td><select id="tax_classes[' . esc_attr( $i ) . ']" name="tax_classes[' . esc_attr( $i ) . ']"><option value="*">' . __('Standard Rate', 'jigoshop') . '</option>';
  1008. if ( $tax_classes ) {
  1009. foreach ( $tax_classes as $class ) :
  1010. echo '<option value="' . sanitize_title( $class ) . '"';
  1011. if ( isset($rate['class']) && $rate['class'] == sanitize_title( $class )) echo 'selected="selected"';
  1012. echo '>' . $class . '</option>';
  1013. endforeach;
  1014. }
  1015. echo '</select></td>';
  1016. echo '<td><input type="text" value="' . esc_attr( $rate['label'] ) . '" name="tax_label[' . esc_attr( $i ) . ']" placeholder="' . __('Online Label', 'jigoshop') . '" size="10" /></td>';
  1017. echo '<td><select name="tax_country[' . esc_attr( $i ) . '][]" id="tax_country_' . esc_attr( $i ) . '" class="tax_select2" multiple="multiple" style="width:220px;">';
  1018. if ( isset($rate['is_all_states']) ) :
  1019. if ( is_array( $applied_all_states ) && !in_array( $tax_rate['country'].$tax_rate['class'], $applied_all_states )) :
  1020. $applied_all_states[] = $tax_rate['country'].$tax_rate['class'];
  1021. jigoshop_countries::country_dropdown_options( $rate['country'], '*', true ); //all-states
  1022. else :
  1023. continue;
  1024. endif;
  1025. else :
  1026. jigoshop_countries::country_dropdown_options( $rate['country'], $rate['state'], true );
  1027. endif;
  1028. echo '</select>';
  1029. echo '<button class="select_none button">'.__('None', 'jigoshop').'</button><button class="button select_us_states">'.__('US States', 'jigoshop').'</button><button class="button select_europe">'.__('EU States', 'jigoshop').'</button></td>';
  1030. echo '<td><input type="text" value="' . esc_attr( $rate['rate'] ) . '" name="tax_rate[' . esc_attr( $i ) . ']" placeholder="' . __('Rate (%)', 'jigoshop') . '" size="6" /></td>';
  1031. echo '<td><input type="checkbox" name="tax_shipping[' . esc_attr( $i ) . ']" ';
  1032. if ( isset( $rate['shipping'] ) && $rate['shipping'] == 'yes' ) echo 'checked="checked"';
  1033. echo ' /></td>';
  1034. echo '<td><input type="checkbox" name="tax_compound[' . esc_attr( $i ) . ']" ';
  1035. if ( isset( $rate['compound'] ) && $rate['compound'] == 'yes' ) echo 'checked="checked"';
  1036. echo ' /></td></tr>';
  1037. ?><script type="text/javascript">
  1038. jQuery(function() {
  1039. jQuery("#tax_country_<?php echo esc_attr( $i ); ?>").select2();
  1040. });
  1041. </script><?php
  1042. endforeach;
  1043. endif;
  1044. ?>
  1045. </tbody>
  1046. </table>
  1047. <div><a href="#" class="add button"><?php _e('+ Add Tax Rule', 'jigoshop'); ?></a></div>
  1048. </div>
  1049. <script type="text/javascript">
  1050. /* <![CDATA[ */
  1051. jQuery(function() {
  1052. jQuery('tr.tax_rate .select_none').live('click', function(){
  1053. jQuery(this).closest('td').find('select option').removeAttr("selected");
  1054. jQuery(this).closest('td').find('select.tax_select2').trigger("change");
  1055. return false;
  1056. });
  1057. jQuery('tr.tax_rate .select_us_states').live('click', function(e){
  1058. jQuery(this).closest('td').find('select optgroup[label="<?php _e( 'United States', 'jigoshop' ); ?>"] option').attr("selected","selected");
  1059. jQuery(this).closest('td').find('select.tax_select2').trigger("change");
  1060. return false;
  1061. });
  1062. jQuery('tr.tax_rate .options select').live('change', function(e){
  1063. jQuery(this).trigger("liszt:updated");
  1064. jQuery(this).closest('td').find('label').text( jQuery(":selected", this).length + ' ' + '<?php _e('countries/states selected', 'jigoshop'); ?>' );
  1065. });
  1066. jQuery('tr.tax_rate .select_europe').live('click', function(e){
  1067. jQuery(this).closest('td').find('option[value="BE"],option[value="FR"],option[value="DE"],option[value="IT"],option[value="LU"],option[value="NL"],option[value="DK"],option[value="IE"],option[value="GR"],option[value="PT"],option[value="ES"],option[value="AT"],option[value="FI"],option[value="SE"],option[value="CY"],option[value="CZ"],option[value="EE"],option[value="HU"],option[value="LV"],option[value="LT"],option[value="MT"],option[value="PL"],option[value="SK"],option[value="SI"],option[value="RO"],option[value="BG"],option[value="IM"],option[value="GB"]').attr("selected","selected");
  1068. jQuery(this).closest('td').find('select.tax_select2').trigger("change");
  1069. return false;
  1070. });
  1071. jQuery('#jigoshop_tax_rates a.add').live('click', function() {
  1072. var size = jQuery('.tax_rate_rules tbody tr').size();
  1073. jQuery('<tr> \
  1074. <td><a href="#" class="remove button">&times;</a></td> \
  1075. <td><select name="tax_classes[' + size + ']"> \
  1076. <option value="*"><?php _e('Standard Rate', 'jigoshop'); ?></option> \
  1077. <?php $tax_classes = $_tax->get_tax_classes(); if ( $tax_classes ) : foreach ( $tax_classes as $class ) : echo '<option value="' . sanitize_title($class) . '">' . $class . '</option>'; endforeach; endif; ?> \
  1078. </select></td> \
  1079. <td><input type="text" name="tax_label[' + size + ']" placeholder="<?php _e('Online Label', 'jigoshop'); ?>" size="10" /></td> \
  1080. <td><select name="tax_country[' + size + '][]" id="tax_country_' + size +'" multiple="multiple" style="width:220px;"> \
  1081. <?php jigoshop_countries::country_dropdown_options('', '', true); ?></select></td> \
  1082. <td><input type="text" name="tax_rate[' + size + ']" placeholder="<?php _e('Rate (%)', 'jigoshop'); ?>" size="6" /> \
  1083. <td><input type="checkbox" name="tax_shipping[' + size + ']" /></td> \
  1084. <td><input type="checkbox" name="tax_compound[' + size + ']" /></td> \
  1085. </tr>'
  1086. ).appendTo('#jigoshop_tax_rates .tax_rate_rules tbody');
  1087. jQuery('#tax_country_' + size).select2();
  1088. return false;
  1089. });
  1090. jQuery('#jigoshop_tax_rates a.remove').live('click', function(){
  1091. var answer = confirm("<?php _e('Delete this rule?', 'jigoshop'); ?>");
  1092. if (answer) jQuery(this).parent().parent().remove();
  1093. return false;
  1094. });
  1095. });
  1096. /* ]]> */
  1097. </script>
  1098. <?php
  1099. $output = ob_get_contents();
  1100. ob_end_clean();
  1101. return $output;
  1102. }
  1103. }
  1104. ?>