PageRenderTime 63ms CodeModel.GetById 24ms RepoModel.GetById 1ms app.codeStats 0ms

/wp-content/plugins/woocommerce/includes/class-wc-ajax.php

https://bitbucket.org/theshipswakecreative/psw
PHP | 1932 lines | 1245 code | 440 blank | 247 comment | 196 complexity | a0443ac4fd1fdf01c8ab4727c4a7bba5 MD5 | raw file
Possible License(s): LGPL-3.0, Apache-2.0

Large files files are truncated, but you can click here to view the full file

  1. <?php
  2. if ( ! defined( 'ABSPATH' ) ) {
  3. exit; // Exit if accessed directly
  4. }
  5. /**
  6. * WooCommerce WC_AJAX
  7. *
  8. * AJAX Event Handler
  9. *
  10. * @class WC_AJAX
  11. * @version 2.2.0
  12. * @package WooCommerce/Classes
  13. * @category Class
  14. * @author WooThemes
  15. */
  16. class WC_AJAX {
  17. /**
  18. * Hook in methods
  19. */
  20. public static function init() {
  21. // woocommerce_EVENT => nopriv
  22. $ajax_events = array(
  23. 'get_refreshed_fragments' => true,
  24. 'apply_coupon' => true,
  25. 'update_shipping_method' => true,
  26. 'update_order_review' => true,
  27. 'add_to_cart' => true,
  28. 'checkout' => true,
  29. 'feature_product' => false,
  30. 'mark_order_complete' => false,
  31. 'mark_order_processing' => false,
  32. 'add_new_attribute' => false,
  33. 'remove_variation' => false,
  34. 'remove_variations' => false,
  35. 'save_attributes' => false,
  36. 'add_variation' => false,
  37. 'link_all_variations' => false,
  38. 'revoke_access_to_download' => false,
  39. 'grant_access_to_download' => false,
  40. 'get_customer_details' => false,
  41. 'add_order_item' => false,
  42. 'add_order_fee' => false,
  43. 'add_order_shipping' => false,
  44. 'add_order_tax' => false,
  45. 'remove_order_item' => false,
  46. 'remove_order_tax' => false,
  47. 'reduce_order_item_stock' => false,
  48. 'increase_order_item_stock' => false,
  49. 'add_order_item_meta' => false,
  50. 'remove_order_item_meta' => false,
  51. 'calc_line_taxes' => false,
  52. 'save_order_items' => false,
  53. 'load_order_items' => false,
  54. 'add_order_note' => false,
  55. 'delete_order_note' => false,
  56. 'json_search_products' => false,
  57. 'json_search_products_and_variations' => false,
  58. 'json_search_downloadable_products_and_variations' => false,
  59. 'json_search_customers' => false,
  60. 'term_ordering' => false,
  61. 'product_ordering' => false,
  62. 'refund_line_items' => false,
  63. 'delete_refund' => false
  64. );
  65. foreach ( $ajax_events as $ajax_event => $nopriv ) {
  66. add_action( 'wp_ajax_woocommerce_' . $ajax_event, array( __CLASS__, $ajax_event ) );
  67. if ( $nopriv ) {
  68. add_action( 'wp_ajax_nopriv_woocommerce_' . $ajax_event, array( __CLASS__, $ajax_event ) );
  69. }
  70. }
  71. add_action( 'wp_ajax_page_slurp', array( 'WC_Gateway_Mijireh', 'page_slurp' ) );
  72. }
  73. /**
  74. * Get a refreshed cart fragment
  75. */
  76. public static function get_refreshed_fragments() {
  77. // Get mini cart
  78. ob_start();
  79. woocommerce_mini_cart();
  80. $mini_cart = ob_get_clean();
  81. // Fragments and mini cart are returned
  82. $data = array(
  83. 'fragments' => apply_filters( 'add_to_cart_fragments', array(
  84. 'div.widget_shopping_cart_content' => '<div class="widget_shopping_cart_content">' . $mini_cart . '</div>'
  85. )
  86. ),
  87. 'cart_hash' => WC()->cart->get_cart() ? md5( json_encode( WC()->cart->get_cart() ) ) : ''
  88. );
  89. wp_send_json( $data );
  90. }
  91. /**
  92. * AJAX apply coupon on checkout page
  93. */
  94. public static function apply_coupon() {
  95. check_ajax_referer( 'apply-coupon', 'security' );
  96. if ( ! empty( $_POST['coupon_code'] ) ) {
  97. WC()->cart->add_discount( sanitize_text_field( $_POST['coupon_code'] ) );
  98. } else {
  99. wc_add_notice( WC_Coupon::get_generic_coupon_error( WC_Coupon::E_WC_COUPON_PLEASE_ENTER ), 'error' );
  100. }
  101. wc_print_notices();
  102. die();
  103. }
  104. /**
  105. * AJAX update shipping method on cart page
  106. */
  107. public static function update_shipping_method() {
  108. check_ajax_referer( 'update-shipping-method', 'security' );
  109. if ( ! defined('WOOCOMMERCE_CART') ) {
  110. define( 'WOOCOMMERCE_CART', true );
  111. }
  112. $chosen_shipping_methods = WC()->session->get( 'chosen_shipping_methods' );
  113. if ( isset( $_POST['shipping_method'] ) && is_array( $_POST['shipping_method'] ) ) {
  114. foreach ( $_POST['shipping_method'] as $i => $value ) {
  115. $chosen_shipping_methods[ $i ] = wc_clean( $value );
  116. }
  117. }
  118. WC()->session->set( 'chosen_shipping_methods', $chosen_shipping_methods );
  119. WC()->cart->calculate_totals();
  120. woocommerce_cart_totals();
  121. die();
  122. }
  123. /**
  124. * AJAX update order review on checkout
  125. */
  126. public static function update_order_review() {
  127. check_ajax_referer( 'update-order-review', 'security' );
  128. if ( ! defined( 'WOOCOMMERCE_CHECKOUT' ) ) {
  129. define( 'WOOCOMMERCE_CHECKOUT', true );
  130. }
  131. if ( 0 == sizeof( WC()->cart->get_cart() ) ) {
  132. echo '<div class="woocommerce-error">' . __( 'Sorry, your session has expired.', 'woocommerce' ) . ' <a href="' . home_url() . '" class="wc-backward">' . __( 'Return to homepage', 'woocommerce' ) . '</a></div>';
  133. die();
  134. }
  135. do_action( 'woocommerce_checkout_update_order_review', $_POST['post_data'] );
  136. $chosen_shipping_methods = WC()->session->get( 'chosen_shipping_methods' );
  137. if ( isset( $_POST['shipping_method'] ) && is_array( $_POST['shipping_method'] ) ) {
  138. foreach ( $_POST['shipping_method'] as $i => $value ) {
  139. $chosen_shipping_methods[ $i ] = wc_clean( $value );
  140. }
  141. }
  142. WC()->session->set( 'chosen_shipping_methods', $chosen_shipping_methods );
  143. WC()->session->set( 'chosen_payment_method', empty( $_POST['payment_method'] ) ? '' : $_POST['payment_method'] );
  144. if ( isset( $_POST['country'] ) ) {
  145. WC()->customer->set_country( $_POST['country'] );
  146. }
  147. if ( isset( $_POST['state'] ) ) {
  148. WC()->customer->set_state( $_POST['state'] );
  149. }
  150. if ( isset( $_POST['postcode'] ) ) {
  151. WC()->customer->set_postcode( $_POST['postcode'] );
  152. }
  153. if ( isset( $_POST['city'] ) ) {
  154. WC()->customer->set_city( $_POST['city'] );
  155. }
  156. if ( isset( $_POST['address'] ) ) {
  157. WC()->customer->set_address( $_POST['address'] );
  158. }
  159. if ( isset( $_POST['address_2'] ) ) {
  160. WC()->customer->set_address_2( $_POST['address_2'] );
  161. }
  162. if ( wc_ship_to_billing_address_only() ) {
  163. if ( isset( $_POST['country'] ) ) {
  164. WC()->customer->set_shipping_country( $_POST['country'] );
  165. }
  166. if ( isset( $_POST['state'] ) ) {
  167. WC()->customer->set_shipping_state( $_POST['state'] );
  168. }
  169. if ( isset( $_POST['postcode'] ) ) {
  170. WC()->customer->set_shipping_postcode( $_POST['postcode'] );
  171. }
  172. if ( isset( $_POST['city'] ) ) {
  173. WC()->customer->set_shipping_city( $_POST['city'] );
  174. }
  175. if ( isset( $_POST['address'] ) ) {
  176. WC()->customer->set_shipping_address( $_POST['address'] );
  177. }
  178. if ( isset( $_POST['address_2'] ) ) {
  179. WC()->customer->set_shipping_address_2( $_POST['address_2'] );
  180. }
  181. } else {
  182. if ( isset( $_POST['s_country'] ) ) {
  183. WC()->customer->set_shipping_country( $_POST['s_country'] );
  184. }
  185. if ( isset( $_POST['s_state'] ) ) {
  186. WC()->customer->set_shipping_state( $_POST['s_state'] );
  187. }
  188. if ( isset( $_POST['s_postcode'] ) ) {
  189. WC()->customer->set_shipping_postcode( $_POST['s_postcode'] );
  190. }
  191. if ( isset( $_POST['s_city'] ) ) {
  192. WC()->customer->set_shipping_city( $_POST['s_city'] );
  193. }
  194. if ( isset( $_POST['s_address'] ) ) {
  195. WC()->customer->set_shipping_address( $_POST['s_address'] );
  196. }
  197. if ( isset( $_POST['s_address_2'] ) ) {
  198. WC()->customer->set_shipping_address_2( $_POST['s_address_2'] );
  199. }
  200. }
  201. WC()->cart->calculate_totals();
  202. do_action( 'woocommerce_checkout_order_review', true ); // Display review order table
  203. die();
  204. }
  205. /**
  206. * AJAX add to cart
  207. */
  208. public static function add_to_cart() {
  209. ob_start();
  210. $product_id = apply_filters( 'woocommerce_add_to_cart_product_id', absint( $_POST['product_id'] ) );
  211. $quantity = empty( $_POST['quantity'] ) ? 1 : wc_stock_amount( $_POST['quantity'] );
  212. $passed_validation = apply_filters( 'woocommerce_add_to_cart_validation', true, $product_id, $quantity );
  213. if ( $passed_validation && WC()->cart->add_to_cart( $product_id, $quantity ) ) {
  214. do_action( 'woocommerce_ajax_added_to_cart', $product_id );
  215. if ( get_option( 'woocommerce_cart_redirect_after_add' ) == 'yes' ) {
  216. wc_add_to_cart_message( $product_id );
  217. }
  218. // Return fragments
  219. self::get_refreshed_fragments();
  220. } else {
  221. // If there was an error adding to the cart, redirect to the product page to show any errors
  222. $data = array(
  223. 'error' => true,
  224. 'product_url' => apply_filters( 'woocommerce_cart_redirect_after_error', get_permalink( $product_id ), $product_id )
  225. );
  226. wp_send_json( $data );
  227. }
  228. die();
  229. }
  230. /**
  231. * Process ajax checkout form
  232. */
  233. public static function checkout() {
  234. if ( ! defined( 'WOOCOMMERCE_CHECKOUT' ) ) {
  235. define( 'WOOCOMMERCE_CHECKOUT', true );
  236. }
  237. WC()->checkout()->process_checkout();
  238. die(0);
  239. }
  240. /**
  241. * Feature a product from admin
  242. */
  243. public static function feature_product() {
  244. if ( ! current_user_can( 'edit_products' ) ) {
  245. wp_die( __( 'You do not have sufficient permissions to access this page.', 'woocommerce' ), '', array( 'response' => 403 ) );
  246. }
  247. if ( ! check_admin_referer( 'woocommerce-feature-product' ) ) {
  248. wp_die( __( 'You have taken too long. Please go back and retry.', 'woocommerce' ), '', array( 'response' => 403 ) );
  249. }
  250. $post_id = ! empty( $_GET['product_id'] ) ? (int) $_GET['product_id'] : '';
  251. if ( ! $post_id || get_post_type( $post_id ) !== 'product' ) {
  252. die;
  253. }
  254. $featured = get_post_meta( $post_id, '_featured', true );
  255. if ( 'yes' === $featured ) {
  256. update_post_meta( $post_id, '_featured', 'no' );
  257. } else {
  258. update_post_meta( $post_id, '_featured', 'yes' );
  259. }
  260. delete_transient( 'wc_featured_products' );
  261. wp_safe_redirect( wp_get_referer() ? remove_query_arg( array( 'trashed', 'untrashed', 'deleted', 'ids' ), wp_get_referer() ) : admin_url( 'edit.php?post_type=shop_order' ) );
  262. die();
  263. }
  264. /**
  265. * Mark an order as complete
  266. */
  267. public static function mark_order_complete() {
  268. if ( ! current_user_can( 'edit_shop_orders' ) ) {
  269. wp_die( __( 'You do not have sufficient permissions to access this page.', 'woocommerce' ), '', array( 'response' => 403 ) );
  270. }
  271. if ( ! check_admin_referer( 'woocommerce-mark-order-complete' ) ) {
  272. wp_die( __( 'You have taken too long. Please go back and retry.', 'woocommerce' ), '', array( 'response' => 403 ) );
  273. }
  274. $order_id = isset( $_GET['order_id'] ) && (int) $_GET['order_id'] ? (int) $_GET['order_id'] : '';
  275. if ( ! $order_id ) {
  276. die();
  277. }
  278. $order = wc_get_order( $order_id );
  279. $order->update_status( 'completed' );
  280. wp_safe_redirect( wp_get_referer() ? wp_get_referer() : admin_url( 'edit.php?post_type=shop_order' ) );
  281. die();
  282. }
  283. /**
  284. * Mark an order as processing
  285. */
  286. public static function mark_order_processing() {
  287. if ( ! current_user_can( 'edit_shop_orders' ) ) {
  288. wp_die( __( 'You do not have sufficient permissions to access this page.', 'woocommerce' ), '', array( 'response' => 403 ) );
  289. }
  290. if ( ! check_admin_referer( 'woocommerce-mark-order-processing' ) ) {
  291. wp_die( __( 'You have taken too long. Please go back and retry.', 'woocommerce' ), '', array( 'response' => 403 ) );
  292. }
  293. $order_id = isset( $_GET['order_id'] ) && (int) $_GET['order_id'] ? (int) $_GET['order_id'] : '';
  294. if ( ! $order_id ) {
  295. die();
  296. }
  297. $order = wc_get_order( $order_id );
  298. $order->update_status( 'processing' );
  299. wp_safe_redirect( wp_get_referer() ? wp_get_referer() : admin_url( 'edit.php?post_type=shop_order' ) );
  300. die();
  301. }
  302. /**
  303. * Add a new attribute via ajax function
  304. */
  305. public static function add_new_attribute() {
  306. ob_start();
  307. check_ajax_referer( 'add-attribute', 'security' );
  308. $taxonomy = esc_attr( $_POST['taxonomy'] );
  309. $term = stripslashes( $_POST['term'] );
  310. if ( taxonomy_exists( $taxonomy ) ) {
  311. $result = wp_insert_term( $term, $taxonomy );
  312. if ( is_wp_error( $result ) ) {
  313. wp_send_json( array(
  314. 'error' => $result->get_error_message()
  315. ) );
  316. } else {
  317. wp_send_json( array(
  318. 'term_id' => $result['term_id'],
  319. 'name' => $term,
  320. 'slug' => sanitize_title( $term ),
  321. ) );
  322. }
  323. }
  324. die();
  325. }
  326. /**
  327. * Delete variation via ajax function
  328. */
  329. public static function remove_variation() {
  330. check_ajax_referer( 'delete-variation', 'security' );
  331. $variation_id = intval( $_POST['variation_id'] );
  332. $variation = get_post( $variation_id );
  333. if ( $variation && 'product_variation' == $variation->post_type ) {
  334. wp_delete_post( $variation_id );
  335. }
  336. die();
  337. }
  338. /**
  339. * Delete variations via ajax function
  340. */
  341. public static function remove_variations() {
  342. check_ajax_referer( 'delete-variations', 'security' );
  343. $variation_ids = (array) $_POST['variation_ids'];
  344. foreach ( $variation_ids as $variation_id ) {
  345. $variation = get_post( $variation_id );
  346. if ( $variation && 'product_variation' == $variation->post_type ) {
  347. wp_delete_post( $variation_id );
  348. }
  349. }
  350. die();
  351. }
  352. /**
  353. * Save attributes via ajax
  354. */
  355. public static function save_attributes() {
  356. check_ajax_referer( 'save-attributes', 'security' );
  357. // Get post data
  358. parse_str( $_POST['data'], $data );
  359. $post_id = absint( $_POST['post_id'] );
  360. // Save Attributes
  361. $attributes = array();
  362. if ( isset( $data['attribute_names'] ) ) {
  363. $attribute_names = array_map( 'stripslashes', $data['attribute_names'] );
  364. $attribute_values = isset( $data['attribute_values'] ) ? $data['attribute_values'] : array();
  365. if ( isset( $data['attribute_visibility'] ) ) {
  366. $attribute_visibility = $data['attribute_visibility'];
  367. }
  368. if ( isset( $data['attribute_variation'] ) ) {
  369. $attribute_variation = $data['attribute_variation'];
  370. }
  371. $attribute_is_taxonomy = $data['attribute_is_taxonomy'];
  372. $attribute_position = $data['attribute_position'];
  373. $attribute_names_count = sizeof( $attribute_names );
  374. for ( $i = 0; $i < $attribute_names_count; $i++ ) {
  375. if ( ! $attribute_names[ $i ] ) {
  376. continue;
  377. }
  378. $is_visible = isset( $attribute_visibility[ $i ] ) ? 1 : 0;
  379. $is_variation = isset( $attribute_variation[ $i ] ) ? 1 : 0;
  380. $is_taxonomy = $attribute_is_taxonomy[ $i ] ? 1 : 0;
  381. if ( $is_taxonomy ) {
  382. if ( isset( $attribute_values[ $i ] ) ) {
  383. // Select based attributes - Format values (posted values are slugs)
  384. if ( is_array( $attribute_values[ $i ] ) ) {
  385. $values = array_map( 'sanitize_title', $attribute_values[ $i ] );
  386. // Text based attributes - Posted values are term names - don't change to slugs
  387. } else {
  388. $values = array_map( 'stripslashes', array_map( 'strip_tags', explode( WC_DELIMITER, $attribute_values[ $i ] ) ) );
  389. }
  390. // Remove empty items in the array
  391. $values = array_filter( $values, 'strlen' );
  392. } else {
  393. $values = array();
  394. }
  395. // Update post terms
  396. if ( taxonomy_exists( $attribute_names[ $i ] ) ) {
  397. wp_set_object_terms( $post_id, $values, $attribute_names[ $i ] );
  398. }
  399. if ( $values ) {
  400. // Add attribute to array, but don't set values
  401. $attributes[ sanitize_title( $attribute_names[ $i ] ) ] = array(
  402. 'name' => wc_clean( $attribute_names[ $i ] ),
  403. 'value' => '',
  404. 'position' => $attribute_position[ $i ],
  405. 'is_visible' => $is_visible,
  406. 'is_variation' => $is_variation,
  407. 'is_taxonomy' => $is_taxonomy
  408. );
  409. }
  410. } elseif ( isset( $attribute_values[ $i ] ) ) {
  411. // Text based, separate by pipe
  412. $values = implode( ' ' . WC_DELIMITER . ' ', array_map( 'wc_clean', array_map( 'stripslashes', explode( WC_DELIMITER, $attribute_values[ $i ] ) ) ) );
  413. // Custom attribute - Add attribute to array and set the values
  414. $attributes[ sanitize_title( $attribute_names[ $i ] ) ] = array(
  415. 'name' => wc_clean( $attribute_names[ $i ] ),
  416. 'value' => $values,
  417. 'position' => $attribute_position[ $i ],
  418. 'is_visible' => $is_visible,
  419. 'is_variation' => $is_variation,
  420. 'is_taxonomy' => $is_taxonomy
  421. );
  422. }
  423. }
  424. }
  425. if ( ! function_exists( 'attributes_cmp' ) ) {
  426. function attributes_cmp( $a, $b ) {
  427. if ( $a['position'] == $b['position'] ) {
  428. return 0;
  429. }
  430. return ( $a['position'] < $b['position'] ) ? -1 : 1;
  431. }
  432. }
  433. uasort( $attributes, 'attributes_cmp' );
  434. update_post_meta( $post_id, '_product_attributes', $attributes );
  435. die();
  436. }
  437. /**
  438. * Add variation via ajax function
  439. */
  440. public static function add_variation() {
  441. check_ajax_referer( 'add-variation', 'security' );
  442. $post_id = intval( $_POST['post_id'] );
  443. $loop = intval( $_POST['loop'] );
  444. $variation = array(
  445. 'post_title' => 'Product #' . $post_id . ' Variation',
  446. 'post_content' => '',
  447. 'post_status' => 'publish',
  448. 'post_author' => get_current_user_id(),
  449. 'post_parent' => $post_id,
  450. 'post_type' => 'product_variation'
  451. );
  452. $variation_id = wp_insert_post( $variation );
  453. do_action( 'woocommerce_create_product_variation', $variation_id );
  454. if ( $variation_id ) {
  455. $variation_post_status = 'publish';
  456. $variation_data = get_post_meta( $variation_id );
  457. $variation_data['variation_post_id'] = $variation_id;
  458. // Get attributes
  459. $attributes = (array) maybe_unserialize( get_post_meta( $post_id, '_product_attributes', true ) );
  460. // Get tax classes
  461. $tax_classes = array_filter(array_map('trim', explode("\n", get_option('woocommerce_tax_classes'))));
  462. $tax_class_options = array();
  463. $tax_class_options['parent'] =__( 'Same as parent', 'woocommerce' );
  464. $tax_class_options[''] = __( 'Standard', 'woocommerce' );
  465. if ( $tax_classes ) {
  466. foreach ( $tax_classes as $class ) {
  467. $tax_class_options[ sanitize_title( $class ) ] = $class;
  468. }
  469. }
  470. $backorder_options = array(
  471. 'no' => __( 'Do not allow', 'woocommerce' ),
  472. 'notify' => __( 'Allow, but notify customer', 'woocommerce' ),
  473. 'yes' => __( 'Allow', 'woocommerce' )
  474. );
  475. $stock_status_options = array(
  476. 'instock' => __( 'In stock', 'woocommerce' ),
  477. 'outofstock' => __( 'Out of stock', 'woocommerce' )
  478. );
  479. // Get parent data
  480. $parent_data = array(
  481. 'id' => $post_id,
  482. 'attributes' => $attributes,
  483. 'tax_class_options' => $tax_class_options,
  484. 'sku' => get_post_meta( $post_id, '_sku', true ),
  485. 'weight' => get_post_meta( $post_id, '_weight', true ),
  486. 'length' => get_post_meta( $post_id, '_length', true ),
  487. 'width' => get_post_meta( $post_id, '_width', true ),
  488. 'height' => get_post_meta( $post_id, '_height', true ),
  489. 'tax_class' => get_post_meta( $post_id, '_tax_class', true ),
  490. 'backorder_options' => $backorder_options,
  491. 'stock_status_options' => $stock_status_options
  492. );
  493. if ( ! $parent_data['weight'] ) {
  494. $parent_data['weight'] = '0.00';
  495. }
  496. if ( ! $parent_data['length'] ) {
  497. $parent_data['length'] = '0';
  498. }
  499. if ( ! $parent_data['width'] ) {
  500. $parent_data['width'] = '0';
  501. }
  502. if ( ! $parent_data['height'] ) {
  503. $parent_data['height'] = '0';
  504. }
  505. $_tax_class = '';
  506. $_downloadable_files = '';
  507. $_stock_status = '';
  508. $_backorders = '';
  509. $image_id = 0;
  510. $variation = get_post( $variation_id ); // Get the variation object
  511. include( 'admin/meta-boxes/views/html-variation-admin.php' );
  512. }
  513. die();
  514. }
  515. /**
  516. * Link all variations via ajax function
  517. */
  518. public static function link_all_variations() {
  519. if ( ! defined( 'WC_MAX_LINKED_VARIATIONS' ) ) {
  520. define( 'WC_MAX_LINKED_VARIATIONS', 49 );
  521. }
  522. check_ajax_referer( 'link-variations', 'security' );
  523. @set_time_limit(0);
  524. $post_id = intval( $_POST['post_id'] );
  525. if ( ! $post_id ) {
  526. die();
  527. }
  528. $variations = array();
  529. $_product = wc_get_product( $post_id, array( 'product_type' => 'variable' ) );
  530. // Put variation attributes into an array
  531. foreach ( $_product->get_attributes() as $attribute ) {
  532. if ( ! $attribute['is_variation'] ) {
  533. continue;
  534. }
  535. $attribute_field_name = 'attribute_' . sanitize_title( $attribute['name'] );
  536. if ( $attribute['is_taxonomy'] ) {
  537. $options = wc_get_product_terms( $post_id, $attribute['name'], array( 'fields' => 'names' ) );
  538. } else {
  539. $options = explode( WC_DELIMITER, $attribute['value'] );
  540. }
  541. $options = array_map( 'sanitize_title', array_map( 'trim', $options ) );
  542. $variations[ $attribute_field_name ] = $options;
  543. }
  544. // Quit out if none were found
  545. if ( sizeof( $variations ) == 0 ) {
  546. die();
  547. }
  548. // Get existing variations so we don't create duplicates
  549. $available_variations = array();
  550. foreach( $_product->get_children() as $child_id ) {
  551. $child = $_product->get_child( $child_id );
  552. if ( ! empty( $child->variation_id ) ) {
  553. $available_variations[] = $child->get_variation_attributes();
  554. }
  555. }
  556. // Created posts will all have the following data
  557. $variation_post_data = array(
  558. 'post_title' => 'Product #' . $post_id . ' Variation',
  559. 'post_content' => '',
  560. 'post_status' => 'publish',
  561. 'post_author' => get_current_user_id(),
  562. 'post_parent' => $post_id,
  563. 'post_type' => 'product_variation'
  564. );
  565. // Now find all combinations and create posts
  566. if ( ! function_exists( 'array_cartesian' ) ) {
  567. /**
  568. * @param array $input
  569. * @return array
  570. */
  571. function array_cartesian( $input ) {
  572. $result = array();
  573. while ( list( $key, $values ) = each( $input ) ) {
  574. // If a sub-array is empty, it doesn't affect the cartesian product
  575. if ( empty( $values ) ) {
  576. continue;
  577. }
  578. // Special case: seeding the product array with the values from the first sub-array
  579. if ( empty( $result ) ) {
  580. foreach ( $values as $value ) {
  581. $result[] = array( $key => $value );
  582. }
  583. }
  584. else {
  585. // Second and subsequent input sub-arrays work like this:
  586. // 1. In each existing array inside $product, add an item with
  587. // key == $key and value == first item in input sub-array
  588. // 2. Then, for each remaining item in current input sub-array,
  589. // add a copy of each existing array inside $product with
  590. // key == $key and value == first item in current input sub-array
  591. // Store all items to be added to $product here; adding them on the spot
  592. // inside the foreach will result in an infinite loop
  593. $append = array();
  594. foreach ( $result as &$product ) {
  595. // Do step 1 above. array_shift is not the most efficient, but it
  596. // allows us to iterate over the rest of the items with a simple
  597. // foreach, making the code short and familiar.
  598. $product[ $key ] = array_shift( $values );
  599. // $product is by reference (that's why the key we added above
  600. // will appear in the end result), so make a copy of it here
  601. $copy = $product;
  602. // Do step 2 above.
  603. foreach ( $values as $item ) {
  604. $copy[ $key ] = $item;
  605. $append[] = $copy;
  606. }
  607. // Undo the side effecst of array_shift
  608. array_unshift( $values, $product[ $key ] );
  609. }
  610. // Out of the foreach, we can add to $results now
  611. $result = array_merge( $result, $append );
  612. }
  613. }
  614. return $result;
  615. }
  616. }
  617. $variation_ids = array();
  618. $added = 0;
  619. $possible_variations = array_cartesian( $variations );
  620. foreach ( $possible_variations as $variation ) {
  621. // Check if variation already exists
  622. if ( in_array( $variation, $available_variations ) ) {
  623. continue;
  624. }
  625. $variation_id = wp_insert_post( $variation_post_data );
  626. $variation_ids[] = $variation_id;
  627. foreach ( $variation as $key => $value ) {
  628. update_post_meta( $variation_id, $key, $value );
  629. }
  630. $added++;
  631. do_action( 'product_variation_linked', $variation_id );
  632. if ( $added > WC_MAX_LINKED_VARIATIONS ) {
  633. break;
  634. }
  635. }
  636. delete_transient( 'wc_product_children_ids_' . $post_id );
  637. echo $added;
  638. die();
  639. }
  640. /**
  641. * Delete download permissions via ajax function
  642. */
  643. public static function revoke_access_to_download() {
  644. check_ajax_referer( 'revoke-access', 'security' );
  645. global $wpdb;
  646. $download_id = $_POST['download_id'];
  647. $product_id = intval( $_POST['product_id'] );
  648. $order_id = intval( $_POST['order_id'] );
  649. $wpdb->query( $wpdb->prepare( "DELETE FROM {$wpdb->prefix}woocommerce_downloadable_product_permissions WHERE order_id = %d AND product_id = %d AND download_id = %s;", $order_id, $product_id, $download_id ) );
  650. do_action( 'woocommerce_ajax_revoke_access_to_product_download', $download_id, $product_id, $order_id );
  651. die();
  652. }
  653. /**
  654. * Grant download permissions via ajax function
  655. */
  656. public static function grant_access_to_download() {
  657. check_ajax_referer( 'grant-access', 'security' );
  658. global $wpdb;
  659. $wpdb->hide_errors();
  660. $order_id = intval( $_POST['order_id'] );
  661. $product_ids = $_POST['product_ids'];
  662. $loop = intval( $_POST['loop'] );
  663. $file_counter = 0;
  664. $order = wc_get_order( $order_id );
  665. if ( ! is_array( $product_ids ) ) {
  666. $product_ids = array( $product_ids );
  667. }
  668. foreach ( $product_ids as $product_id ) {
  669. $product = wc_get_product( $product_id );
  670. $files = $product->get_files();
  671. if ( ! $order->billing_email ) {
  672. die();
  673. }
  674. if ( $files ) {
  675. foreach ( $files as $download_id => $file ) {
  676. if ( $inserted_id = wc_downloadable_file_permission( $download_id, $product_id, $order ) ) {
  677. // insert complete - get inserted data
  678. $download = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM {$wpdb->prefix}woocommerce_downloadable_product_permissions WHERE permission_id = %d", $inserted_id ) );
  679. $loop ++;
  680. $file_counter ++;
  681. if ( isset( $file['name'] ) ) {
  682. $file_count = $file['name'];
  683. } else {
  684. $file_count = sprintf( __( 'File %d', 'woocommerce' ), $file_counter );
  685. }
  686. include( 'admin/meta-boxes/views/html-order-download-permission.php' );
  687. }
  688. }
  689. }
  690. }
  691. die();
  692. }
  693. /**
  694. * Get customer details via ajax
  695. */
  696. public static function get_customer_details() {
  697. ob_start();
  698. check_ajax_referer( 'get-customer-details', 'security' );
  699. $user_id = (int) trim(stripslashes($_POST['user_id']));
  700. $type_to_load = esc_attr(trim(stripslashes($_POST['type_to_load'])));
  701. $customer_data = array(
  702. $type_to_load . '_first_name' => get_user_meta( $user_id, $type_to_load . '_first_name', true ),
  703. $type_to_load . '_last_name' => get_user_meta( $user_id, $type_to_load . '_last_name', true ),
  704. $type_to_load . '_company' => get_user_meta( $user_id, $type_to_load . '_company', true ),
  705. $type_to_load . '_address_1' => get_user_meta( $user_id, $type_to_load . '_address_1', true ),
  706. $type_to_load . '_address_2' => get_user_meta( $user_id, $type_to_load . '_address_2', true ),
  707. $type_to_load . '_city' => get_user_meta( $user_id, $type_to_load . '_city', true ),
  708. $type_to_load . '_postcode' => get_user_meta( $user_id, $type_to_load . '_postcode', true ),
  709. $type_to_load . '_country' => get_user_meta( $user_id, $type_to_load . '_country', true ),
  710. $type_to_load . '_state' => get_user_meta( $user_id, $type_to_load . '_state', true ),
  711. $type_to_load . '_email' => get_user_meta( $user_id, $type_to_load . '_email', true ),
  712. $type_to_load . '_phone' => get_user_meta( $user_id, $type_to_load . '_phone', true ),
  713. );
  714. $customer_data = apply_filters( 'woocommerce_found_customer_details', $customer_data );
  715. wp_send_json( $customer_data );
  716. }
  717. /**
  718. * Add order item via ajax
  719. */
  720. public static function add_order_item() {
  721. check_ajax_referer( 'order-item', 'security' );
  722. $item_to_add = sanitize_text_field( $_POST['item_to_add'] );
  723. $order_id = absint( $_POST['order_id'] );
  724. // Find the item
  725. if ( ! is_numeric( $item_to_add ) ) {
  726. die();
  727. }
  728. $post = get_post( $item_to_add );
  729. if ( ! $post || ( 'product' !== $post->post_type && 'product_variation' !== $post->post_type ) ) {
  730. die();
  731. }
  732. $_product = wc_get_product( $post->ID );
  733. $order = wc_get_order( $order_id );
  734. $order_taxes = $order->get_taxes();
  735. $class = 'new_row';
  736. // Set values
  737. $item = array();
  738. $item['product_id'] = $_product->id;
  739. $item['variation_id'] = isset( $_product->variation_id ) ? $_product->variation_id : '';
  740. $item['variation_data'] = $item['variation_id'] ? $_product->get_variation_attributes() : '';
  741. $item['name'] = $_product->get_title();
  742. $item['tax_class'] = $_product->get_tax_class();
  743. $item['qty'] = 1;
  744. $item['line_subtotal'] = wc_format_decimal( $_product->get_price_excluding_tax() );
  745. $item['line_subtotal_tax'] = '';
  746. $item['line_total'] = wc_format_decimal( $_product->get_price_excluding_tax() );
  747. $item['line_tax'] = '';
  748. // Add line item
  749. $item_id = wc_add_order_item( $order_id, array(
  750. 'order_item_name' => $item['name'],
  751. 'order_item_type' => 'line_item'
  752. ) );
  753. // Add line item meta
  754. if ( $item_id ) {
  755. wc_add_order_item_meta( $item_id, '_qty', $item['qty'] );
  756. wc_add_order_item_meta( $item_id, '_tax_class', $item['tax_class'] );
  757. wc_add_order_item_meta( $item_id, '_product_id', $item['product_id'] );
  758. wc_add_order_item_meta( $item_id, '_variation_id', $item['variation_id'] );
  759. wc_add_order_item_meta( $item_id, '_line_subtotal', $item['line_subtotal'] );
  760. wc_add_order_item_meta( $item_id, '_line_subtotal_tax', $item['line_subtotal_tax'] );
  761. wc_add_order_item_meta( $item_id, '_line_total', $item['line_total'] );
  762. wc_add_order_item_meta( $item_id, '_line_tax', $item['line_tax'] );
  763. // Since 2.2
  764. wc_add_order_item_meta( $item_id, '_line_tax_data', array( 'total' => array(), 'subtotal' => array() ) );
  765. // Store variation data in meta
  766. if ( $item['variation_data'] && is_array( $item['variation_data'] ) ) {
  767. foreach ( $item['variation_data'] as $key => $value ) {
  768. wc_add_order_item_meta( $item_id, str_replace( 'attribute_', '', $key ), $value );
  769. }
  770. }
  771. do_action( 'woocommerce_ajax_add_order_item_meta', $item_id, $item );
  772. }
  773. $item = apply_filters( 'woocommerce_ajax_order_item', $item, $item_id );
  774. include( 'admin/meta-boxes/views/html-order-item.php' );
  775. // Quit out
  776. die();
  777. }
  778. /**
  779. * Add order fee via ajax
  780. */
  781. public static function add_order_fee() {
  782. check_ajax_referer( 'order-item', 'security' );
  783. $order_id = absint( $_POST['order_id'] );
  784. $order = wc_get_order( $order_id );
  785. $order_taxes = $order->get_taxes();
  786. $item = array();
  787. // Add new fee
  788. $fee = new stdClass();
  789. $fee->name = '';
  790. $fee->tax_class = '';
  791. $fee->taxable = $fee->tax_class !== '0';
  792. $fee->amount = '';
  793. $fee->tax = '';
  794. $fee->tax_data = array();
  795. $item_id = $order->add_fee( $fee );
  796. include( 'admin/meta-boxes/views/html-order-fee.php' );
  797. // Quit out
  798. die();
  799. }
  800. /**
  801. * Add order shipping cost via ajax
  802. */
  803. public static function add_order_shipping() {
  804. check_ajax_referer( 'order-item', 'security' );
  805. $order_id = absint( $_POST['order_id'] );
  806. $order = wc_get_order( $order_id );
  807. $order_taxes = $order->get_taxes();
  808. $shipping_methods = WC()->shipping() ? WC()->shipping->load_shipping_methods() : array();
  809. $item = array();
  810. // Add new shipping
  811. $shipping = new stdClass();
  812. $shipping->label = '';
  813. $shipping->id = '';
  814. $shipping->cost = '';
  815. $shipping->taxes = array();
  816. $item_id = $order->add_shipping( $shipping );
  817. include( 'admin/meta-boxes/views/html-order-shipping.php' );
  818. // Quit out
  819. die();
  820. }
  821. /**
  822. * Add order tax column via ajax
  823. */
  824. public static function add_order_tax() {
  825. global $wpdb;
  826. check_ajax_referer( 'order-item', 'security' );
  827. $order_id = absint( $_POST['order_id'] );
  828. $rate_id = absint( $_POST['rate_id'] );
  829. $order = new WC_Order( $order_id );
  830. $data = get_post_meta( $order_id );
  831. // Add new tax
  832. $order->add_tax( $rate_id, 0, 0 );
  833. // Return HTML items
  834. include( 'admin/meta-boxes/views/html-order-items.php' );
  835. die();
  836. }
  837. /**
  838. * Remove an order item
  839. */
  840. public static function remove_order_item() {
  841. check_ajax_referer( 'order-item', 'security' );
  842. $order_item_ids = $_POST['order_item_ids'];
  843. if ( ! is_array( $order_item_ids ) && is_numeric( $order_item_ids ) ) {
  844. $order_item_ids = array( $order_item_ids );
  845. }
  846. if ( sizeof( $order_item_ids ) > 0 ) {
  847. foreach( $order_item_ids as $id ) {
  848. wc_delete_order_item( absint( $id ) );
  849. }
  850. }
  851. die();
  852. }
  853. /**
  854. * Remove an order tax
  855. */
  856. public static function remove_order_tax() {
  857. check_ajax_referer( 'order-item', 'security' );
  858. $order_id = absint( $_POST['order_id'] );
  859. $rate_id = absint( $_POST['rate_id'] );
  860. wc_delete_order_item( $rate_id );
  861. // Return HTML items
  862. $order = new WC_Order( $order_id );
  863. $data = get_post_meta( $order_id );
  864. include( 'admin/meta-boxes/views/html-order-items.php' );
  865. die();
  866. }
  867. /**
  868. * Reduce order item stock
  869. */
  870. public static function reduce_order_item_stock() {
  871. check_ajax_referer( 'order-item', 'security' );
  872. $order_id = absint( $_POST['order_id'] );
  873. $order_item_ids = isset( $_POST['order_item_ids'] ) ? $_POST['order_item_ids'] : array();
  874. $order_item_qty = isset( $_POST['order_item_qty'] ) ? $_POST['order_item_qty'] : array();
  875. $order = wc_get_order( $order_id );
  876. $order_items = $order->get_items();
  877. $return = array();
  878. if ( $order && ! empty( $order_items ) && sizeof( $order_item_ids ) > 0 ) {
  879. foreach ( $order_items as $item_id => $order_item ) {
  880. // Only reduce checked items
  881. if ( ! in_array( $item_id, $order_item_ids ) ) {
  882. continue;
  883. }
  884. $_product = $order->get_product_from_item( $order_item );
  885. if ( $_product->exists() && $_product->managing_stock() && isset( $order_item_qty[ $item_id ] ) && $order_item_qty[ $item_id ] > 0 ) {
  886. $stock_change = apply_filters( 'woocommerce_reduce_order_stock_quantity', $order_item_qty[ $item_id ], $item_id );
  887. $new_stock = $_product->reduce_stock( $stock_change );
  888. $return[] = sprintf( __( 'Item #%s stock reduced from %s to %s.', 'woocommerce' ), $order_item['product_id'], $new_stock + $stock_change, $new_stock );
  889. $order->add_order_note( sprintf( __( 'Item #%s stock reduced from %s to %s.', 'woocommerce' ), $order_item['product_id'], $new_stock + $stock_change, $new_stock ) );
  890. $order->send_stock_notifications( $_product, $new_stock, $order_item_qty[ $item_id ] );
  891. }
  892. }
  893. do_action( 'woocommerce_reduce_order_stock', $order );
  894. if ( empty( $return ) ) {
  895. $return[] = __( 'No products had their stock reduced - they may not have stock management enabled.', 'woocommerce' );
  896. }
  897. echo implode( ', ', $return );
  898. }
  899. die();
  900. }
  901. /**
  902. * Increase order item stock
  903. */
  904. public static function increase_order_item_stock() {
  905. check_ajax_referer( 'order-item', 'security' );
  906. $order_id = absint( $_POST['order_id'] );
  907. $order_item_ids = isset( $_POST['order_item_ids'] ) ? $_POST['order_item_ids'] : array();
  908. $order_item_qty = isset( $_POST['order_item_qty'] ) ? $_POST['order_item_qty'] : array();
  909. $order = wc_get_order( $order_id );
  910. $order_items = $order->get_items();
  911. $return = array();
  912. if ( $order && ! empty( $order_items ) && sizeof( $order_item_ids ) > 0 ) {
  913. foreach ( $order_items as $item_id => $order_item ) {
  914. // Only reduce checked items
  915. if ( ! in_array( $item_id, $order_item_ids ) ) {
  916. continue;
  917. }
  918. $_product = $order->get_product_from_item( $order_item );
  919. if ( $_product->exists() && $_product->managing_stock() && isset( $order_item_qty[ $item_id ] ) && $order_item_qty[ $item_id ] > 0 ) {
  920. $old_stock = $_product->stock;
  921. $stock_change = apply_filters( 'woocommerce_restore_order_stock_quantity', $order_item_qty[ $item_id ], $item_id );
  922. $new_quantity = $_product->increase_stock( $stock_change );
  923. $return[] = sprintf( __( 'Item #%s stock increased from %s to %s.', 'woocommerce' ), $order_item['product_id'], $old_stock, $new_quantity );
  924. $order->add_order_note( sprintf( __( 'Item #%s stock increased from %s to %s.', 'woocommerce' ), $order_item['product_id'], $old_stock, $new_quantity ) );
  925. }
  926. }
  927. do_action( 'woocommerce_restore_order_stock', $order );
  928. if ( empty( $return ) ) {
  929. $return[] = __( 'No products had their stock increased - they may not have stock management enabled.', 'woocommerce' );
  930. }
  931. echo implode( ', ', $return );
  932. }
  933. die();
  934. }
  935. /**
  936. * Add some meta to a line item
  937. */
  938. public static function add_order_item_meta() {
  939. check_ajax_referer( 'order-item', 'security' );
  940. $meta_id = wc_add_order_item_meta( absint( $_POST['order_item_id'] ), __( 'Name', 'woocommerce' ), __( 'Value', 'woocommerce' ) );
  941. if ( $meta_id ) {
  942. echo '<tr data-meta_id="' . esc_attr( $meta_id ) . '"><td><input type="text" name="meta_key[' . $meta_id . ']" /><textarea name="meta_value[' . $meta_id . ']"></textarea></td><td width="1%"><button class="remove_order_item_meta button">&times;</button></td></tr>';
  943. }
  944. die();
  945. }
  946. /**
  947. * Remove meta from a line item
  948. */
  949. public static function remove_order_item_meta() {
  950. global $wpdb;
  951. check_ajax_referer( 'order-item', 'security' );
  952. $meta_id = absint( $_POST['meta_id'] );
  953. $wpdb->query( $wpdb->prepare( "DELETE FROM {$wpdb->prefix}woocommerce_order_itemmeta WHERE meta_id = %d", $meta_id ) );
  954. die();
  955. }
  956. /**
  957. * Calc line tax
  958. */
  959. public static function calc_line_taxes() {
  960. global $wpdb;
  961. check_ajax_referer( 'calc-totals', 'security' );
  962. $tax = new WC_Tax();
  963. $order_id = absint( $_POST['order_id'] );
  964. $items = array();
  965. $country = strtoupper( esc_attr( $_POST['country'] ) );
  966. $state = strtoupper( esc_attr( $_POST['state'] ) );
  967. $postcode = strtoupper( esc_attr( $_POST['postcode'] ) );
  968. $city = sanitize_title( esc_attr( $_POST['city'] ) );
  969. $order = wc_get_order( $order_id );
  970. $taxes = array();
  971. $shipping_taxes = array();
  972. // Parse the jQuery serialized items
  973. parse_str( $_POST['items'], $items );
  974. // Prevent undefined warnings
  975. if ( ! isset( $items['line_tax'] ) ) {
  976. $items['line_tax'] = array();
  977. }
  978. if ( ! isset( $items['line_subtotal_tax'] ) ) {
  979. $items['line_subtotal_tax'] = array();
  980. }
  981. $items['order_taxes'] = array();
  982. // Get items and fees taxes
  983. if ( isset( $items['order_item_id'] ) ) {
  984. $get_values = array( 'order_item_id', 'line_subtotal', 'line_total', 'order_item_tax_class' );
  985. foreach ( $get_values as $value ) {
  986. $$value = isset( $items[ $value ] ) ? $items[ $value ] : array();
  987. }
  988. foreach ( $order_item_id as $item_id ) {
  989. $item_id = absint( $item_id );
  990. $line_total[ $item_id ] = isset( $line_total[ $item_id ] ) ? wc_format_decimal( $line_total[ $item_id ] ) : 0;
  991. $line_subtotal[ $item_id ] = isset( $line_subtotal[ $item_id ] ) ? wc_format_decimal( $line_subtotal[ $item_id ] ) : $line_total[ $item_id ];
  992. $order_item_tax_class[ $item_id ] = isset( $order_item_tax_class[ $item_id ] ) ? sanitize_text_field( $order_item_tax_class[ $item_id ] ) : '';
  993. $product_id = $order->get_item_meta( $item_id, '_product_id', true );
  994. // Get product details
  995. if ( get_post_type( $product_id ) == 'product' ) {
  996. $_product = wc_get_product( $product_id );
  997. $item_tax_status = $_product->get_tax_status();
  998. } else {
  999. $item_tax_status = 'taxable';
  1000. }
  1001. if ( '0' !== $order_item_tax_class[ $item_id ] && 'taxable' === $item_tax_status ) {
  1002. $tax_rates = WC_Tax::find_rates( array(
  1003. 'country' => $country,
  1004. 'state' => $state,
  1005. 'postcode' => $postcode,
  1006. 'city' => $city,
  1007. 'tax_class' => $order_item_tax_class[ $item_id ]
  1008. ) );
  1009. $line_taxes = WC_Tax::calc_tax( $line_total[ $item_id ], $tax_rates, false );
  1010. $line_subtotal_taxes = WC_Tax::calc_tax( $line_subtotal[ $item_id ], $tax_rates, false );
  1011. // Set the new line_tax
  1012. foreach ( $line_taxes as $_tax_id => $_tax_value ) {
  1013. $items['line_tax'][ $item_id ][ $_tax_id ] = $_tax_value;
  1014. }
  1015. // Set the new line_subtotal_tax
  1016. foreach ( $line_subtotal_taxes as $_tax_id => $_tax_value ) {
  1017. $items['line_subtotal_tax'][ $item_id ][ $_tax_id ] = $_tax_value;
  1018. }
  1019. // Sum the item taxes
  1020. foreach ( array_keys( $taxes + $line_taxes ) as $key ) {
  1021. $taxes[ $key ] = ( isset( $line_taxes[ $key ] ) ? $line_taxes[ $key ] : 0 ) + ( isset( $taxes[ $key ] ) ? $taxes[ $key ] : 0 );
  1022. }
  1023. }
  1024. }
  1025. }
  1026. // Get shipping taxes
  1027. if ( isset( $items['shipping_method_id'] ) ) {
  1028. $matched_tax_rates = array();
  1029. $tax_rates = WC_Tax::find_rates( array(
  1030. 'country' => $country,
  1031. 'state' => $state,
  1032. 'postcode' => $postcode,
  1033. 'city' => $city,
  1034. 'tax_class' => ''
  1035. ) );
  1036. if ( $tax_rates ) {
  1037. foreach ( $tax_rates as $key => $rate ) {
  1038. if ( isset( $rate['shipping'] ) && 'yes' == $rate['shipping'] ) {
  1039. $matched_tax_rates[ $key ] = $rate;
  1040. }
  1041. }
  1042. }
  1043. $get_values = array( 'shipping_method_id', 'shipping_cost', 'shipping_taxes' );
  1044. foreach ( $get_values as $value ) {
  1045. $$value = isset( $items[ $value ] ) ? $items[ $value ] : array();
  1046. }
  1047. foreach ( $shipping_method_id as $item_id ) {
  1048. $item_id = absint( $item_id );
  1049. $shipping_cost[ $item_id ] = isset( $shipping_cost[ $item_id ] ) ? wc_format_decimal( $shipping_cost[ $item_id ] ) : 0;
  1050. $shipping_taxes = WC_Tax::calc_shipping_tax( $shipping_cost[ $item_id ], $matched_tax_rates );
  1051. // Set the new shipping_taxes
  1052. foreach ( $shipping_taxes as $_tax_id => $_tax_value ) {
  1053. $items['shipping_taxes'][ $item_id ][ $_tax_id ] = $_tax_value;
  1054. }
  1055. }
  1056. }
  1057. // Remove old tax rows
  1058. $order->remove_order_items( 'tax' );
  1059. // Add tax rows
  1060. foreach ( array_keys( $taxes + $shipping_taxes ) as $tax_rate_id ) {
  1061. $order->add_tax( $tax_rate_id, isset( $taxes[ $tax_rate_id ] ) ? $taxes[ $tax_rate_id ] : 0, isset( $shipping_taxes[ $tax_rate_id ] ) ? $shipping_taxes[ $tax_rate_id ] : 0 );
  1062. }
  1063. // Create the new order_taxes
  1064. foreach ( $order->get_taxes() as $tax_id => $tax_item ) {
  1065. $items['order_taxes'][ $tax_id ] = absint( $tax_item['rate_id'] );
  1066. }
  1067. // Save order items
  1068. wc_save_order_items( $order_id, $items );
  1069. // Return HTML items
  1070. $order = new WC_Order( $order_id );
  1071. $data = get_post_meta( $order_id );
  1072. include( 'admin/meta-boxes/views/html-order-items.php' );
  1073. die();
  1074. }
  1075. /**
  1076. * Save order items via ajax
  1077. */
  1078. public static function save_order_items() {
  1079. check_ajax_referer( 'order-item', 'security' );
  1080. if ( isset( $_POST['order_id'] ) && isset( $_POST['items'] ) ) {
  1081. $order_id = absint( $_POST['order_id'] );
  1082. // Parse the jQuery serialized items
  1083. $items = array();
  1084. parse_str( $_POST['items'], $items );
  1085. // Save order items
  1086. wc_save_order_items( $order_id, $items );
  1087. // Return HTML items
  1088. $order = new WC_Order( $order_id );
  1089. $data = get_post_meta( $order_id );
  1090. include( 'admin/meta-boxes/views/html-order-items.php' );
  1091. }
  1092. die();
  1093. }
  1094. /**
  1095. * Load order items via ajax
  1096. */
  1097. public static function load_order_items() {
  1098. check_ajax_referer( 'order-item', 'security' );
  1099. // Return HTML items
  1100. $order_id = absint( $_POST['order_id'] );
  1101. $order = new WC_Order( $order_id );
  1102. $data = get_post_meta( $order_id );
  1103. include( 'admin/meta-boxes/views/html-order-items.php' );
  1104. die();
  1105. }
  1106. /**
  1107. * Add order note via ajax
  1108. */
  1109. public static function add_order_note() {
  1110. check_ajax_referer( 'add-order-note', 'security' );
  1111. $post_id = (int) $_POST['post_id'];
  1112. $note = wp_kses_post( trim( stripslashes( $_POST['note'] ) ) );
  1113. $note_type = $_POST['note_type'];
  1114. $is_customer_note = $note_type == 'customer' ? 1 : 0;
  1115. if ( $post_id > 0 ) {
  1116. $order = wc_get_order( $post_id );
  1117. $comment_id = $order->add_order_note( $note, $is_customer_note );
  1118. echo '<li rel="' . esc_attr( $comment_id ) . '" class="note ';
  1119. if ( $is_customer_note ) {
  1120. echo 'customer-note';
  1121. }
  1122. echo '"><div class="note_content">';
  1123. echo wpautop( wptexturize( $note ) );
  1124. echo '</div><p class="meta"><a href="#" class="delete_note">'.__( 'Delete note', 'woocommerce' ).'</a></p>';
  1125. echo '</li>';
  1126. }
  1127. // Quit out
  1128. die();
  1129. }
  1130. /**
  1131. * Delete order note via ajax
  1132. */
  1133. public static function delete_order_note() {
  1134. check_ajax_referer( 'delete-order-note', 'security' );
  1135. $note_id = (int) $_POST['note_id'];
  1136. if ( $note_id > 0 ) {
  1137. wp_delete_comment( $note_id );
  1138. }
  1139. // Quit out
  1140. die();
  1141. }
  1142. /**
  1143. * Search for products and echo json
  1144. *
  1145. * @param string $x (default: '')
  1146. * @param string $post_types (default: array('product'))
  1147. */
  1148. public static function json_search_products( $x = '', $post_types = array('product') ) {
  1149. ob_start();
  1150. check_ajax_referer( 'search-products', 'security' );
  1151. $term = (string) wc_clean( stripslashes( $_GET['term'] ) );
  1152. if ( empty( $term ) ) {
  1153. die();
  1154. }
  1155. if ( is_numeric( $term ) ) {
  1156. $args = array(
  1157. 'post_type' => $post_types,
  1158. 'post_status' => 'publish',
  1159. 'posts_per_page' => -1,
  1160. 'post__in' => array(0, $term),
  1161. 'fields' => 'ids'
  1162. );
  1163. $args2 = array(
  1164. 'post_type' => $post_types,
  1165. 'post_status' => 'publish',
  1166. 'posts_per_page' => -1,
  1167. 'post_parent' => $term,
  1168. 'fields' => 'ids'
  1169. );
  1170. $args3 = array(
  1171. 'post_type' => $post_types,
  1172. 'post_status' => 'publish',
  1173. 'posts_per_page' => -1,
  1174. 'meta_query' => array(
  1175. array(
  1176. 'key' => '_sku',
  1177. 'value' => $term,
  1178. 'compare' => 'LIKE'
  1179. )
  1180. ),
  1181. 'fields' => 'ids'
  1182. );
  1183. $posts = array_unique( array_merge( get_posts( $args ), get_posts( $args2 ), get_posts( $args3 ) ) );
  1184. } else {
  1185. $args = array(
  1186. 'post_type' => $post_types,
  1187. 'post_status' => 'publish',
  1188. 'posts_per_page' => -1,
  1189. 's' => $term,
  1190. 'fields' => 'ids'
  1191. );
  1192. $args2 = array(
  1193. 'post_type' => $post_types,
  1194. 'post_status' => 'publish',
  1195. 'posts_per_page' => -1,
  1196. 'meta_query' => array(
  1197. array(
  1198. 'key' => '_sku',
  1199. 'value' => $term,
  1200. 'compare' => 'LIKE'
  1201. )
  1202. ),
  1203. 'fields' => 'ids'
  1204. );
  1205. $posts = array_unique( array_merge( get_posts( $args ), get_posts( $args2 ) ) );
  1206. }
  1207. $found_products = array();
  1208. if ( $posts ) {
  1209. foreach ( $posts as $post ) {
  1210. $product = wc_get_product( $post );
  1211. $found_products[ $post ] = $product->get_formatted_name();
  1212. }
  1213. }
  1214. $found_products = apply_filters( 'woocommerce_json_search_found_products', $found_products );
  1215. wp_send_json( $found_products );
  1216. }
  1217. /**
  1218. * Search for product variations and return json
  1219. *
  1220. * @access public
  1221. * @return void
  1222. * @see WC_AJAX::json_search_products()
  1223. */
  1224. public static function json_search_products_and_variations() {
  1225. self::json_search_products( '', array('product', 'product_variation') );
  1226. }
  1227. /**
  1228. * Search for customers and return json
  1229. */
  1230. public static function json_search_customers() {
  1231. ob_start();
  1232. check_ajax_referer( 'search-customers', 'security' );
  1233. $term = wc_clean( stripslashes( $_GET['term'] ) );
  1234. if ( empty( $term ) ) {
  1235. die();
  1236. }
  1237. $default = isset( $_GET['default'] ) ? $_GET['default'] : __( 'Guest', 'woocommerce' );
  1238. $found_customers = array( '' => $default );
  1239. add_action( 'pre_user_query', array( __CLASS__, 'json_search_customer_name' ) );
  1240. $customers_query = new WP_User_Query( apply_filters( 'woocommerce_json_search_customers_query', array(
  1241. 'fields' => 'all',
  1242. 'orderby' => 'display_name',
  1243. 'search' => '*' . $term . '*',
  1244. 'search_columns' => array( 'ID', 'user_login', 'user_email', 'user_nicename' )
  1245. ) ) );
  1246. remove_action( 'pre_user_query', array( __CLASS__, 'json_search_customer_name' ) );
  1247. $customers = $customers_query->get_results();
  1248. if ( $customers ) {
  1249. foreach ( $customers as $customer ) {
  1250. $found_customers[ $customer->ID ] = $customer->display_name . ' (#' . $customer->ID . ' &ndash; ' . sanitize_email( $customer->user_email ) . ')';
  1251. }
  1252. }
  1253. wp_send_json( $found_customers );
  1254. }
  1255. /**
  1256. * Search for downloadable product variations and return json
  1257. *
  1258. * @access public
  1259. * @return void
  1260. * @see WC_AJAX::json_search_products()
  1261. */
  1262. public static function json_search_downloadable_products_and_variations() {
  1263. ob_start();
  1264. $term = (string) wc_clean( stripslashes( $_GET['term'] ) );
  1265. $args = array(
  1266. 'post_type' => array( 'product', 'product_variation' ),
  1267. 'posts_per_page' => -1,
  1268. 'post_status' => 'publish',
  1269. 'order' => 'ASC',
  1270. 'orderby' => 'parent title',
  1271. 'meta_query' => array(
  1272. array(
  1273. 'key' => '_downloadable',
  1274. 'value' => 'yes'
  1275. )
  1276. ),
  1277. 's' => $term
  1278. );
  1279. $posts = get_posts( $args );
  1280. $found_products = array();
  1281. if ( $posts ) {
  1282. foreach ( $posts as $post ) {
  1283. $product = wc_get_product( $post->ID );

Large files files are truncated, but you can click here to view the full file