/wpsc-admin/ajax.php

  1. <?php 
  2.  
  3. /** 
  4. * Verify nonce of an AJAX request 
  5. * 
  6. * @since 3.8.9 
  7. * @access private 
  8. * 
  9. * @uses WP_Error WordPress Error Class 
  10. * @uses wp_verify_nonce() Verify that correct nonce was used with time limit. 
  11. * 
  12. * @param string $ajax_action Name of AJAX action 
  13. * @return WP_Error|boolean True if nonce is valid. WP_Error if otherwise. 
  14. */ 
  15. function _wpsc_ajax_verify_nonce( $ajax_action ) { 
  16. // nonce can be passed with name wpsc_nonce or _wpnonce 
  17. $nonce = ''; 
  18.  
  19. if ( isset( $_REQUEST['nonce'] ) ) 
  20. $nonce = $_REQUEST['nonce']; 
  21. elseif ( isset( $_REQUEST['_wpnonce'] ) ) 
  22. $nonce = $_REQUEST['_wpnonce']; 
  23. else 
  24. return _wpsc_error_invalid_nonce(); 
  25.  
  26. // validate nonce 
  27. if ( ! wp_verify_nonce( $nonce, 'wpsc_ajax_' . $ajax_action ) ) 
  28. return _wpsc_error_invalid_nonce(); 
  29.  
  30. return true; 
  31.  
  32. function _wpsc_error_invalid_nonce() { 
  33. return new WP_Error( 'wpsc_ajax_invalid_nonce', __( 'Your session has expired. Please refresh the page and try again.', 'wpsc' ) ); 
  34.  
  35. /** 
  36. * Verify AJAX callback and call it if it exists. 
  37. * 
  38. * @since 3.8.9 
  39. * @access private 
  40. * 
  41. * @uses WP_Error WordPress Error object 
  42. * 
  43. * @param string $ajax_action Name of AJAX action 
  44. * @return WP_Error|array Array of response args if callback is valid. WP_Error if otherwise. 
  45. */ 
  46. function _wpsc_ajax_fire_callback( $ajax_action ) { 
  47. // if callback exists, call it and output JSON response 
  48. $callback = "_wpsc_ajax_{$ajax_action}"; 
  49.  
  50. if ( is_callable( $callback ) ) 
  51. $result = call_user_func( $callback ); 
  52. else 
  53. $result = new WP_Error( 'wpsc_invalid_ajax_callback', __( 'Invalid AJAX callback.', 'wpsc' ) ); 
  54.  
  55. return $result; 
  56.  
  57. /** 
  58. * AJAX handler for all WPEC ajax requests. 
  59. * 
  60. * This function automates nonce checking and outputs JSON response. 
  61. * 
  62. * @since 3.8.9 
  63. * @access private 
  64. * 
  65. * @uses _wpsc_ajax_fire_callback() Verify ajax callback if it exists 
  66. * @uses _wpsc_ajax_verify_nonce() Verify nonce of an ajax request 
  67. * @uses is_wp_error() Check whether variable is a WordPress Error. 
  68. * 
  69. * @return array $output json encoded response 
  70. */ 
  71. function _wpsc_ajax_handler() { 
  72. $ajax_action = str_replace( '-', '_', $_REQUEST['wpsc_action'] ); 
  73.  
  74. if ( is_callable( '_wpsc_ajax_verify_' . $ajax_action ) ) 
  75. $result = call_user_func( '_wpsc_ajax_verify_' . $ajax_action ); 
  76. else 
  77. $result = _wpsc_ajax_verify_nonce( $ajax_action ); 
  78.  
  79. if ( ! is_wp_error( $result ) ) 
  80. $result = _wpsc_ajax_fire_callback( $ajax_action ); 
  81.  
  82. $output = array( 
  83. 'is_successful' => false,  
  84. ); 
  85.  
  86. if ( is_wp_error( $result ) ) { 
  87. $output['error'] = array( 
  88. 'code' => $result->get_error_code(),  
  89. 'messages' => $result->get_error_messages(),  
  90. 'data' => $result->get_error_data(),  
  91. ); 
  92. } else { 
  93. $output['is_successful'] = true; 
  94. $output['obj'] = $result; 
  95.  
  96. echo json_encode( $output ); 
  97. exit; 
  98. add_action( 'wp_ajax_wpsc_ajax', '_wpsc_ajax_handler' ); 
  99.  
  100. /** 
  101. * Checks if WPSC is doing ajax 
  102. * 
  103. * @param string $action req The action we're checking 
  104. * @return bool True if doing ajax 
  105. */ 
  106. function wpsc_is_doing_ajax( $action = '' ) { 
  107. $ajax = defined( 'DOING_AJAX' ) && DOING_AJAX && ! empty( $_REQUEST['action'] ) && $_REQUEST['action'] == 'wpsc_ajax'; 
  108.  
  109. if ( $action ) 
  110. $ajax = $ajax && ! empty( $_REQUEST['wpsc_action'] ) && $action == str_replace( '-', '_', $_REQUEST['wpsc_action'] ); 
  111.  
  112. return $ajax; 
  113.  
  114. /** 
  115. * Helper function that generates nonce for an AJAX action. Basically just a wrapper of 
  116. * wp_create_nonce() but automatically add prefix. 
  117. * 
  118. * @since 3.8.9 
  119. * @access private 
  120. * 
  121. * @uses wp_create_nonce() Creates a random one time use token 
  122. * 
  123. * @param string $action AJAX action without prefix 
  124. * @return string The generated nonce. 
  125. */ 
  126. function _wpsc_create_ajax_nonce( $ajax_action ) { 
  127. return wp_create_nonce( "wpsc_ajax_{$ajax_action}" ); 
  128.  
  129. /** 
  130. * Add new variation set via AJAX. 
  131. * 
  132. * If the variation set name is the same as an existing variation set,  
  133. * the children variant terms will be added inside that existing set. 
  134. * 
  135. * @since 3.8.8 
  136. * @access private 
  137. * 
  138. * @uses term_exists() Returns true if term exists 
  139. * @uses get_term() Gets all term data by term_id 
  140. * @uses wp_insert_term() Inserts a term to the WordPress database 
  141. * @uses is_wp_error() Checks whether variable is a WordPress error 
  142. * @uses WP_Error WordPress Error class 
  143. * @uses clean_term_cache() Will remove all of the term ids from the cache. 
  144. * @uses delete_option() Deletes option from the database 
  145. * @uses wp_cache_set() Saves the data to the cache. 
  146. * @uses _get_term_hierarchy() Retrieves children of taxonomy as Term IDs. 
  147. * @uses wp_terms_checklist() Output an unordered list of checkbox <input> elements labelled 
  148. * @uses WPSC_Walker_Variation_Checklist Walker variation checklist 
  149. * 
  150. * @return array Response args 
  151. */ 
  152. function _wpsc_ajax_add_variation_set() { 
  153. $new_variation_set = $_POST['variation_set']; 
  154. $variants = preg_split( '/\s*, \s*/', $_POST['variants'] ); 
  155.  
  156. $return = array(); 
  157.  
  158. $parent_term_exists = term_exists( $new_variation_set, 'wpsc-variation' ); 
  159.  
  160. // only use an existing parent ID if the term is not a child term 
  161. if ( $parent_term_exists ) { 
  162. $parent_term = get_term( $parent_term_exists['term_id'], 'wpsc-variation' ); 
  163. if ( $parent_term->parent == '0' ) 
  164. $variation_set_id = $parent_term_exists['term_id']; 
  165.  
  166. if ( empty( $variation_set_id ) ) { 
  167. $results = wp_insert_term( apply_filters( 'wpsc_new_variation_set', $new_variation_set ), 'wpsc-variation' ); 
  168. if ( is_wp_error( $results ) ) 
  169. return $results; 
  170. $variation_set_id = $results['term_id']; 
  171.  
  172. if ( empty( $variation_set_id ) ) 
  173. return new WP_Error( 'wpsc_invalid_variation_id', __( 'Cannot retrieve the variation set in order to proceed.', 'wpsc' ) ); 
  174.  
  175. foreach ( $variants as $variant ) { 
  176. $results = wp_insert_term( apply_filters( 'wpsc_new_variant', $variant, $variation_set_id ), 'wpsc-variation', array( 'parent' => $variation_set_id ) ); 
  177.  
  178. if ( is_wp_error( $results ) ) 
  179. return $results; 
  180.  
  181. $inserted_variants[] = $results['term_id']; 
  182.  
  183. require_once( 'includes/walker-variation-checklist.php' ); 
  184.  
  185. if ( ! version_compare( $GLOBALS['wp_version'], '3.8.3', '>' ) ) { 
  186.  
  187. /** --- DIRTY HACK START --- */ 
  188. /** 
  189. There's a bug with term cache in WordPress core. See http://core.trac.wordpress.org/ticket/14485. Fixed in 3.9. 
  190. The next 3 lines will delete children term cache for wpsc-variation. 
  191. Without this hack, the new child variations won't be displayed on "Variations" page and 
  192. also won't be displayed in wp_terms_checklist() call below. 
  193. */ 
  194. clean_term_cache( $variation_set_id, 'wpsc-variation' ); 
  195. delete_option('wpsc-variation_children'); 
  196. wp_cache_set( 'last_changed', 1, 'terms' ); 
  197. _get_term_hierarchy('wpsc-variation'); 
  198. /** --- DIRTY HACK END --- */ 
  199.  
  200.  
  201. ob_start(); 
  202.  
  203. wp_terms_checklist( (int) $_POST['post_id'], array( 
  204. 'taxonomy' => 'wpsc-variation',  
  205. 'descendants_and_self' => $variation_set_id,  
  206. 'walker' => new WPSC_Walker_Variation_Checklist( $inserted_variants ),  
  207. 'checked_ontop' => false,  
  208. ) ); 
  209.  
  210. $content = ob_get_clean(); 
  211.  
  212. $return = array( 
  213. 'variation_set_id' => $variation_set_id,  
  214. 'inserted_variants' => $inserted_variants,  
  215. 'content' => $content,  
  216. ); 
  217.  
  218. return $return; 
  219.  
  220. /** 
  221. * Display gateway settings form via AJAX 
  222. * 
  223. * @since 3.8.9 
  224. * @access private 
  225. * 
  226. * @uses WPSC_Settings_Tab_Gateway 
  227. * @uses WPSC_Settings_Tab_Gateway::display_payment_gateway_settings_form() Displays payment gateway form 
  228. * 
  229. * @return array Response args 
  230. */ 
  231. function _wpsc_ajax_payment_gateway_settings_form() { 
  232. require_once( 'settings-page.php' ); 
  233. require_once( 'includes/settings-tabs/gateway.php' ); 
  234.  
  235. $return = array(); 
  236. ob_start(); 
  237. $tab = new WPSC_Settings_Tab_Gateway(); 
  238. $tab->display_payment_gateway_settings_form(); 
  239. $return['content'] = ob_get_clean(); 
  240.  
  241. return $return; 
  242.  
  243. /** 
  244. * Display shipping module settings form via AJAX 
  245. * 
  246. * @since 3.8.9 
  247. * @access private 
  248. * 
  249. * @uses WPSC_Settings_Table_Shipping 
  250. * @uses WPSC_Settings_Table_Shipping::display_shipping_module_settings_form() Displays shipping module form 
  251. * 
  252. * @return array $return Response args 
  253. */ 
  254. function _wpsc_ajax_shipping_module_settings_form() { 
  255. require_once( 'settings-page.php' ); 
  256. require_once( 'includes/settings-tabs/shipping.php' ); 
  257.  
  258. $return = array(); 
  259. ob_start(); 
  260. $tab = new WPSC_Settings_Tab_Shipping(); 
  261. $tab->display_shipping_module_settings_form(); 
  262. $return['content'] = ob_get_clean(); 
  263.  
  264. return $return; 
  265.  
  266. /** 
  267. * Display settings tab via AJAX 
  268. * 
  269. * @since 3.8.9 
  270. * @access private 
  271. * 
  272. * @uses WPSC_Settings_Page 
  273. * @uses WPSC_Settings_Page::display_current_tab() Shows current tab of settings page 
  274. * 
  275. * @return array $return Response args 
  276. */ 
  277. function _wpsc_ajax_navigate_settings_tab() { 
  278. require_once( 'settings-page.php' ); 
  279.  
  280. $return = array(); 
  281. ob_start(); 
  282. $settings_page = new WPSC_Settings_Page( $_POST['tab'] ); 
  283. $settings_page->display_current_tab(); 
  284. $return['content'] = ob_get_clean(); 
  285.  
  286. return $return; 
  287.  
  288. /** 
  289. * Display base region list in Store Settings -> General 
  290. * 
  291. * @since 3.8.9 
  292. * @access private 
  293. * 
  294. * @uses WPSC_Settings_Tab_General 
  295. * @uses WPSC_Settings_Tab_General::display_region_drop_down() Shows region dropdown 
  296. * 
  297. * @return array $return Response args 
  298. */ 
  299. function _wpsc_ajax_display_region_list() { 
  300. require_once( 'settings-page.php' ); 
  301. require_once( 'includes/settings-tabs/general.php' ); 
  302.  
  303. $return = array(); 
  304. ob_start(); 
  305. $tab = new WPSC_Settings_Tab_General(); 
  306. $tab->display_region_drop_down(); 
  307. $return['content'] = ob_get_clean(); 
  308.  
  309. return $return; 
  310.  
  311. /** 
  312. * Save tracking ID of a sales log. 
  313. * 
  314. * @since 3.8.9 
  315. * @access private 
  316. * 
  317. * @uses WP_Error WordPress Error class 
  318. * 
  319. * @return array|WP_Error $return Response args if successful, WP_Error if otherwise. 
  320. */ 
  321. function _wpsc_ajax_purchase_log_save_tracking_id() { 
  322. global $wpdb; 
  323.  
  324. $result = $wpdb->update( 
  325. WPSC_TABLE_PURCHASE_LOGS,  
  326. array( 
  327. 'track_id' => $_POST['value'] 
  328. ),  
  329. array( 
  330. 'id' => $_POST['log_id'] 
  331. ),  
  332. '%s',  
  333. '%d' 
  334. ); 
  335.  
  336. if ( ! $result ) 
  337. return new WP_Error( 'wpsc_cannot_save_tracking_id', __( "Couldn't save tracking ID of the transaction. Please try again.", 'wpsc' ) ); 
  338.  
  339. $return = array( 
  340. 'rows_affected' => $result,  
  341. 'id' => $_POST['log_id'],  
  342. 'track_id' => $_POST['value'],  
  343. ); 
  344.  
  345. return $return; 
  346.  
  347. /** 
  348. * Send sales log tracking email via AJAX 
  349. * 
  350. * @since 3.8.9 
  351. * @access private 
  352. * 
  353. * @uses $wpdb WordPress database object for queries 
  354. * @uses get_option() Gets option from DB given key 
  355. * @uses add_filter() Calls 'wp_mail_from' which can replace the from email address 
  356. * @uses add_filter() Calls 'wp_mail_from_name' allows replacement of the from name on WordPress emails 
  357. * @uses wp_mail() All the emailses in WordPress are sent through this function 
  358. * @uses WP_Error WordPress Error class 
  359. * 
  360. * @return array|WP_Error $return Response args if successful, WP_Error if otherwise 
  361. */ 
  362. function _wpsc_ajax_purchase_log_send_tracking_email() { 
  363. global $wpdb; 
  364.  
  365. $id = absint( $_POST['log_id'] ); 
  366. $sql = $wpdb->prepare( "SELECT `track_id` FROM " . WPSC_TABLE_PURCHASE_LOGS . " WHERE `id`=%d LIMIT 1", $id ); 
  367. $trackingid = $wpdb->get_var( $sql ); 
  368.  
  369. $message = get_option( 'wpsc_trackingid_message' ); 
  370. $message = str_replace( '%trackid%', $trackingid, $message ); 
  371. $message = str_replace( '%shop_name%', get_option( 'blogname' ), $message ); 
  372.  
  373. $email = wpsc_get_buyers_email( $id ); 
  374.  
  375. $subject = get_option( 'wpsc_trackingid_subject' ); 
  376. $subject = str_replace( '%shop_name%', get_option( 'blogname' ), $subject ); 
  377.  
  378. add_filter( 'wp_mail_from', 'wpsc_replace_reply_address', 0 ); 
  379. add_filter( 'wp_mail_from_name', 'wpsc_replace_reply_name', 0 ); 
  380.  
  381. $result = wp_mail( $email, $subject, $message); 
  382.  
  383. if ( ! $result ) 
  384. return new WP_Error( 'wpsc_cannot_send_tracking_email', __( "Couldn't send tracking email. Please try again.", 'wpsc' ) ); 
  385.  
  386. $return = array( 
  387. 'id' => $id,  
  388. 'tracking_id' => $trackingid,  
  389. 'subject' => $subject,  
  390. 'message' => $message,  
  391. 'email' => $email 
  392. ); 
  393.  
  394. return $return; 
  395.  
  396. /** 
  397. * Do purchase log action link via AJAX 
  398. * 
  399. * @since 3.9.0 
  400. * @access private 
  401. * 
  402. * @return array|WP_Error $return Response args if successful, WP_Error if otherwise 
  403. */ 
  404. function _wpsc_ajax_purchase_log_action_link() { 
  405.  
  406. if ( isset( $_POST['log_id'] ) && isset( $_POST['purchase_log_action_link'] ) && isset( $_POST['purchase_log_action_nonce'] ) ) { 
  407.  
  408. $log_id = absint( $_POST['log_id'] ); 
  409. $purchase_log_action_link = sanitize_key( $_POST['purchase_log_action_link'] ); 
  410.  
  411. // Verify action nonce 
  412. if ( wp_verify_nonce( $_POST['purchase_log_action_nonce'], 'wpsc_purchase_log_action_ajax_' . $purchase_log_action_link ) ) { 
  413.  
  414. // Expected to receive success = true by default, or false on error. 
  415. $return = apply_filters( 'wpsc_purchase_log_action_ajax-' . $purchase_log_action_link, array( 'success' => null ), $log_id ); 
  416.  
  417. } else { 
  418. $return = _wpsc_error_invalid_nonce(); 
  419.  
  420. if ( ! is_wp_error( $return ) ) { 
  421. $return['log_id'] = $log_id; 
  422. $return['purchase_log_action_link'] = $purchase_log_action_link; 
  423. $return['success'] = isset( $return['success'] ) ? (bool) $return['success'] : null; 
  424.  
  425. return $return; 
  426.  
  427.  
  428. return new WP_Error( 'wpsc_ajax_invalid_purchase_log_action', __( 'Purchase log action failed.', 'wpsc' ) ); 
  429.  
  430.  
  431. /** 
  432. * Handle AJAX clear downloads lock purchase log action 
  433. * 
  434. * The _wpsc_ajax_purchase_log_action_link() function which triggers this function is nonce 
  435. * and capability checked in _wpsc_ajax_handler(). 
  436. * 
  437. * @since 3.9.0 
  438. * @access private 
  439. * 
  440. * @param array $response AJAX response. 
  441. * @param int $log_id Purchase log ID. 
  442. */ 
  443. function wpsc_purchase_log_action_ajax_downloads_lock( $response, $log_id ) { 
  444.  
  445. $response['success'] = wpsc_purchlog_clear_download_items( $log_id ); 
  446.  
  447. return $response; 
  448.  
  449. add_action( 'wpsc_purchase_log_action_ajax-downloads_lock', 'wpsc_purchase_log_action_ajax_downloads_lock', 10, 2 ); 
  450.  
  451.  
  452. /** 
  453. * Handle AJAX email receipt purchase log action 
  454. * 
  455. * The _wpsc_ajax_purchase_log_action_link() function which triggers this function is nonce 
  456. * and capability checked in _wpsc_ajax_handler(). 
  457. * 
  458. * @since 3.9.0 
  459. * @access private 
  460. * 
  461. * @param array $response AJAX response. 
  462. * @param int $log_id Purchase log ID. 
  463. */ 
  464. function wpsc_purchase_log_action_ajax_email_receipt( $response, $log_id ) { 
  465.  
  466. $response['success'] = wpsc_purchlog_resend_email( $log_id ); 
  467.  
  468. return $response; 
  469.  
  470. add_action( 'wpsc_purchase_log_action_ajax-email_receipt', 'wpsc_purchase_log_action_ajax_email_receipt', 10, 2 ); 
  471.  
  472. /** 
  473. * Delete an attached downloadable file via AJAX. 
  474. * 
  475. * @since 3.8.9 
  476. * @access private 
  477. * 
  478. * @uses _wpsc_delete_file() Deletes files associated with a product 
  479. * @uses WP_Error WordPress error class 
  480. * 
  481. * @return array|WP_Error $return Response args if successful, WP_Error if otherwise 
  482. */ 
  483. function _wpsc_ajax_delete_file() { 
  484. $product_id = absint( $_REQUEST['product_id'] ); 
  485. $file_name = basename( $_REQUEST['file_name'] ); 
  486.  
  487. $result = _wpsc_delete_file( $product_id, $file_name ); 
  488.  
  489. if ( ! $result ) 
  490. return new WP_Error( 'wpsc_cannot_delete_file', __( "Couldn't delete the file. Please try again.", 'wpsc' ) ); 
  491.  
  492. $return = array( 
  493. 'product_id' => $product_id,  
  494. 'file_name' => $file_name,  
  495. ); 
  496.  
  497. return $return; 
  498.  
  499. /** 
  500. * Delete a product meta via AJAX 
  501. * 
  502. * @since 3.8.9 
  503. * @access private 
  504. * 
  505. * @uses delete_meta() Deletes metadata by meta id 
  506. * @uses WP_Error WordPress error class 
  507. * 
  508. * @return array|WP_Error $return Response args if successful, WP_Error if otherwise 
  509. */ 
  510. function _wpsc_ajax_remove_product_meta() { 
  511. $meta_id = (int) $_POST['meta_id']; 
  512. if ( ! delete_meta( $meta_id ) ) 
  513. return new WP_Error( 'wpsc_cannot_delete_product_meta', __( "Couldn't delete product meta. Please try again.", 'wpsc' ) ); 
  514.  
  515. return array( 'meta_id' => $meta_id ); 
  516.  
  517. /** 
  518. * Modify a purchase log's status. 
  519. * 
  520. * @since 3.8.9 
  521. * @access private 
  522. * 
  523. * @uses wpsc_purchlog_edit_status() Edits purchase log status 
  524. * @uses WP_Error WordPress Error class 
  525. * @uses WPSC_Purchase_Log_List_Table 
  526. * @uses WPSC_Purchase_Log_List_Table::prepare_items() 
  527. * @uses WPSC_Purchase_Log_List_Table::views() 
  528. * @uses WPSC_Purchase_Log_List_Table::display_tablenav() @todo docs 
  529. * 
  530. * @return array|WP_Error $return Response args if successful, WP_Error if otherwise. 
  531. */ 
  532. function _wpsc_ajax_change_purchase_log_status() { 
  533. $result = wpsc_purchlog_edit_status( $_POST['id'], $_POST['new_status'] ); 
  534. if ( ! $result ) 
  535. return new WP_Error( 'wpsc_cannot_edit_purchase_log_status', __( "Couldn't modify purchase log's status. Please try again.", 'wpsc' ) ); 
  536.  
  537. $args = array(); 
  538.  
  539. $args['screen'] = 'dashboard_page_wpsc-sales-logs'; 
  540.  
  541. require_once( WPSC_FILE_PATH . '/wpsc-admin/includes/purchase-log-list-table-class.php' ); 
  542. $purchaselog_table = new WPSC_Purchase_Log_List_Table( $args ); 
  543. $purchaselog_table->prepare_items(); 
  544.  
  545. ob_start(); 
  546. $purchaselog_table->views(); 
  547. $views = ob_get_clean(); 
  548.  
  549. ob_start(); 
  550. $purchaselog_table->display_tablenav( 'top' ); 
  551. $tablenav_top = ob_get_clean(); 
  552.  
  553. ob_start(); 
  554. $purchaselog_table->display_tablenav( 'bottom' ); 
  555. $tablenav_bottom = ob_get_clean(); 
  556.  
  557. $return = array( 
  558. 'id' => $_POST['id'],  
  559. 'new_status' => $_POST['new_status'],  
  560. 'views' => $views,  
  561. 'tablenav_top' => $tablenav_top,  
  562. 'tablenav_bottom' => $tablenav_bottom,  
  563. ); 
  564.  
  565. return $return; 
  566.  
  567. /** 
  568. * Save product ordering after drag-and-drop sorting 
  569. * 
  570. * @since 3.8.9 
  571. * @access private 
  572. * 
  573. * @uses $wpdb WordPress database object for use in queries 
  574. * @uses wp_update_post() Updates post based on passed $args. Needs a post_id 
  575. * @uses WP_Error WordPress Error class 
  576. * 
  577. * @return array|WP_Error Response args if successful, WP_Error if otherwise 
  578. */ 
  579. function _wpsc_ajax_save_product_order() { 
  580.  
  581. $products = array( ); 
  582. foreach ( $_POST['post'] as $product ) { 
  583. $products[] = (int) str_replace( 'post-', '', $product ); 
  584.  
  585. $failed = array(); 
  586. foreach ( $products as $order => $product_id ) { 
  587. $result = wp_update_post( array( 
  588. 'ID' => $product_id,  
  589. 'menu_order' => $order,  
  590. ) ); 
  591.  
  592. if ( ! $result ) 
  593. $failed[] = $product_id; 
  594.  
  595. // Validate data before exposing to action 
  596. $category = isset( $_POST['category_id'] ) ? get_term_by( 'slug', $_POST['category_id'], 'wpsc_product_category' ) : false; 
  597. do_action( 'wpsc_save_product_order', $products, $category ); 
  598.  
  599. if ( ! empty( $failed ) ) { 
  600. $error_data = array( 
  601. 'failed_ids' => $failed,  
  602. ); 
  603.  
  604. return new WP_Error( 'wpsc_cannot_save_product_sort_order', __( "Couldn't save the products' sort order. Please try again.", 'wpsc' ), $error_data ); 
  605.  
  606. return array( 
  607. 'ids' => $products,  
  608. ); 
  609.  
  610. /** 
  611. * Save Category Product Order 
  612. * 
  613. * Note that this uses the 'term_order' field in the 'term_relationships' table to store 
  614. * the order. Although this column presently seems to be unused by WordPress, the intention 
  615. * is it should be used to store the order of terms associates to a post, not the order 
  616. * of posts as we are doing. This shouldn't be an issue for WPEC unless WordPress adds a UI 
  617. * for this. More info at http://core.trac.wordpress.org/ticket/9547 
  618. * 
  619. * @since 3.9 
  620. * @access private 
  621. * 
  622. * @uses $wpdb WordPress database object used for queries 
  623. */ 
  624. function _wpsc_save_category_product_order( $products, $category ) { 
  625. global $wpdb; 
  626.  
  627. // Only save category product order if in category 
  628. if ( ! $category ) 
  629. return; 
  630.  
  631. // Save product order in term_relationships table 
  632. foreach ( $products as $order => $product_id ) { 
  633. $wpdb->update( $wpdb->term_relationships,  
  634. array( 'term_order' => $order ),  
  635. array( 'object_id' => $product_id, 'term_taxonomy_id' => $category->term_taxonomy_id ),  
  636. array( '%d' ),  
  637. array( '%d', '%d' ) 
  638. ); 
  639. add_action( 'wpsc_save_product_order', '_wpsc_save_category_product_order', 10, 2 ); 
  640.  
  641. /** 
  642. * Update Checkout fields order 
  643. * 
  644. * @since 3.8.9 
  645. * @access private 
  646. * 
  647. * @uses $wpdb WordPress database object used for queries 
  648. * @uses WP_Error WordPress error class 
  649. * 
  650. * @return array|WP_Error Response args or WP_Error 
  651. */ 
  652. function _wpsc_ajax_update_checkout_fields_order() { 
  653. global $wpdb; 
  654.  
  655. $checkout_fields = $_REQUEST['sort_order']; 
  656. $order = 1; 
  657. $failed = array(); 
  658. $modified = array(); 
  659. foreach ( $checkout_fields as &$checkout_field ) { 
  660. // ignore new fields 
  661. if ( strpos( $checkout_field, 'new-field' ) === 0 ) 
  662. continue; 
  663. $checkout_field = absint( preg_replace('/[^0-9]+/', '', $checkout_field ) ); 
  664. $result = $wpdb->update( 
  665. WPSC_TABLE_CHECKOUT_FORMS,  
  666. array( 
  667. 'checkout_order' => $order 
  668. ),  
  669. array( 
  670. 'id' => $checkout_field 
  671. ),  
  672. '%d',  
  673. '%d' 
  674. ); 
  675. $order ++; 
  676. if ( $result === false ) 
  677. $failed[] = $checkout_field; 
  678. elseif ( $result > 0 ) 
  679. $modified[] = $checkout_field; 
  680.  
  681. if ( ! empty( $failed ) ) 
  682. return new WP_Error( 'wpsc_cannot_save_checkout_field_sort_order', __( "Couldn't save checkout field sort order. Please try again.", 'wpsc' ), array( 'failed_ids' => $failed ) ); 
  683.  
  684. return array( 
  685. 'modified' => $modified,  
  686. ); 
  687.  
  688. /** 
  689. * Save a downloadable file to a product 
  690. * 
  691. * @since 3.8.9 
  692. * @access private 
  693. * 
  694. * @uses $wpdb WordPress database object for use in queries 
  695. * @uses _wpsc_create_ajax_nonce() Creates nonce for an ajax action 
  696. * @uses wpsc_get_mimetype() Returns mimetype of file 
  697. * @uses wp_insert_post() Inserts post to WordPress database 
  698. * @uses wp_nonce_url() Retrieve URL with nonce added to URL query. 
  699. * @uses wpsc_convert_bytes() Formats bytes 
  700. * @uses wpsc_get_extension() Gets extension of file 
  701. * @uses esc_attr() Escapes HTML attributes 
  702. * @uses _x() Retrieve translated string with gettext context 
  703. * 
  704. * @return array|WP_Error Response args if successful, WP_Error if otherwise. 
  705. */ 
  706. function _wpsc_ajax_upload_product_file() { 
  707. global $wpdb; 
  708. $product_id = absint( $_POST["product_id"] ); 
  709. $output = ''; 
  710. $delete_nonce = _wpsc_create_ajax_nonce( 'delete_file' ); 
  711.  
  712. foreach ( $_POST["select_product_file"] as $selected_file ) { 
  713. // if we already use this file, there is no point doing anything more. 
  714. $sql = $wpdb->prepare( "SELECT * FROM $wpdb->posts WHERE post_type = 'wpsc-product-file' AND post_title = %s", $selected_file ); // TODO it's safer to select by post ID, in that case we will use get_posts() 
  715. $file_post_data = $wpdb->get_row( $sql, ARRAY_A ); 
  716. $selected_file_path = WPSC_FILE_DIR . basename( $selected_file ); 
  717. $file_url = WPSC_FILE_URL . basename( $selected_file ); 
  718. $file_size = filesize( $selected_file_path ); 
  719. if ( empty( $file_post_data ) ) { 
  720. $type = wpsc_get_mimetype( $selected_file_path ); 
  721. $attachment = array( 
  722. 'post_mime_type' => $type,  
  723. 'post_parent' => $product_id,  
  724. 'post_title' => $selected_file,  
  725. 'post_content' => '',  
  726. 'post_type' => "wpsc-product-file",  
  727. 'post_status' => 'inherit' 
  728. ); 
  729. $id = wp_insert_post( $attachment ); 
  730. } else { 
  731. // already attached 
  732. if ( $file_post_data['post_parent'] == $product_id ) 
  733. continue; 
  734. $type = $file_post_data["post_mime_type"]; 
  735. $url = $file_post_data["guid"]; 
  736. $title = $file_post_data["post_title"]; 
  737. $content = $file_post_data["post_content"]; 
  738. // Construct the attachment 
  739. $attachment = array( 
  740. 'post_mime_type' => $type,  
  741. 'guid' => $url,  
  742. 'post_parent' => absint( $product_id ),  
  743. 'post_title' => $title,  
  744. 'post_content' => $content,  
  745. 'post_type' => "wpsc-product-file",  
  746. 'post_status' => 'inherit' 
  747. ); 
  748. // Save the data 
  749. $id = wp_insert_post( $attachment ); 
  750.  
  751. $deletion_url = wp_nonce_url( "admin.php?wpsc_admin_action=delete_file&file_name={$attachment['post_title']}&product_id={$product_id}", 'delete_file_' . $attachment['post_title'] ); 
  752.  
  753. $output .= '<tr class="wpsc_product_download_row">'; 
  754. $output .= '<td style="padding-right: 30px;">' . $attachment['post_title'] . '</td>'; 
  755. $output .= '<td>' . wpsc_convert_byte( $file_size ) . '</td>'; 
  756. $output .= '<td>.' . wpsc_get_extension( $attachment['post_title'] ) . '</td>'; 
  757. $output .= "<td><a data-file-name='" . esc_attr( $attachment['post_title'] ) . "' data-product-id='" . esc_attr( $product_id ) . "' data-nonce='" . esc_attr( $delete_nonce ) . "' class='file_delete_button' href='{$deletion_url}' >" . _x( 'Delete', 'Digital Download UI row', 'wpsc' ) . "</a></td>"; 
  758. $output .= '<td><a href=' .$file_url .'>' . _x( 'Download', 'Digital Download UI row', 'wpsc' ) . '</a></td>'; 
  759. $output .= '</tr>'; 
  760.  
  761. return array( 
  762. 'content' => $output,  
  763. ); 
  764.  
  765. /** 
  766. * Generate variations 
  767. * 
  768. * @since 3.8.9 
  769. * @access private 
  770. * 
  771. * @uses wpsc_update_variations() Updates product variations given 
  772. * @uses wpsc_admin_product_listing() DEPRECATED 
  773. * 
  774. * @return array|WP_Error Response args if successful, WP_Error if otherwise 
  775. */ 
  776. function _wpsc_ajax_update_variations() { 
  777. $product_id = absint( $_REQUEST["product_id"] ); 
  778. wpsc_update_variations(); 
  779.  
  780. ob_start(); 
  781. wpsc_admin_product_listing( $product_id ); 
  782. $content = ob_get_clean(); 
  783.  
  784. return array( 'content' => $content ); 
  785.  
  786. /** 
  787. * Display the shortcode generator. 
  788. * 
  789. * @since 3.8.9 
  790. * @access private 
  791. */ 
  792. function _wpsc_action_tinymce_window() { 
  793. require_once( WPSC_CORE_JS_PATH . '/tinymce3/window.php' ); 
  794. exit; 
  795. add_action( 'wp_ajax_wpsc_tinymce_window', '_wpsc_action_tinymce_window' ); 
  796.  
  797. /** 
  798. * Add tax rate 
  799. * @since 3.8.9 
  800. * @access private 
  801. * 
  802. * @uses wpec_taxes_controller Contains all the logic to communicate with the taxes system 
  803. * @uses wpec_taxes_controller::wpec_taxes::wpec_taxes_get_regions() Gets tax regions based on input country code 
  804. * @uses wpec_taxes_controller::wpec_taxes_build_select_options() Returns HTML formatted options from input array 
  805. * @uses wpec_taxes_controller::wpec_taxes_build_form() Builds the tax rate form 
  806. * @uses wpec_taxes_controller::wpec_taxes::wpec_taxes_get_band_from_index() Retrieves tax band for given name 
  807. * 
  808. * @return array|WP_Error Response args if successful, WP_Error if otherwise 
  809. */ 
  810. function _wpsc_ajax_add_tax_rate() { 
  811. //include taxes controller 
  812. $wpec_taxes_controller = new wpec_taxes_controller; 
  813.  
  814. switch ( $_REQUEST['wpec_taxes_action'] ) { 
  815. case 'wpec_taxes_get_regions': 
  816. $regions = $wpec_taxes_controller->wpec_taxes->wpec_taxes_get_regions( $_REQUEST['country_code'] ); 
  817. $key = $_REQUEST['current_key']; 
  818. $type = $_REQUEST['taxes_type']; 
  819. $default_option = array( 'region_code' => 'all-markets', 'name' => 'All Markets' ); 
  820. $select_settings = array( 
  821. 'id' => "{$type}-region-{$key}",  
  822. 'name' => "wpsc_options[wpec_taxes_{$type}][{$key}][region_code]",  
  823. 'class' => 'wpsc-taxes-region-drop-down' 
  824. ); 
  825. $returnable = $wpec_taxes_controller->wpec_taxes_build_select_options( $regions, 'region_code', 'name', $default_option, $select_settings ); 
  826. break; 
  827. }// switch 
  828.  
  829. return array( 
  830. 'content' => $returnable,  
  831. ); 
  832.  
  833. /** 
  834. * Displays the WPSC product variations table 
  835. * 
  836. * @uses check_admin_referrer() Makes sure user was referred from another admin page 
  837. * @uses WPSC_Product_Variations_Page The WPSC Product variations class 
  838. * @uses WPSC_Product_Variations_Page::display() Displays the product variations page 
  839. */ 
  840. function wpsc_product_variations_table() { 
  841. check_admin_referer( 'wpsc_product_variations_table' ); 
  842. set_current_screen( 'wpsc-product' ); 
  843. require_once( WPSC_FILE_PATH . '/wpsc-admin/includes/product-variations-page.class.php' ); 
  844. $page = new WPSC_Product_Variations_Page(); 
  845. $page->display(); 
  846.  
  847. exit; 
  848. add_action( 'wp_ajax_wpsc_product_variations_table', 'wpsc_product_variations_table' ); 
  849.  
  850. /** 
  851. * @access private 
  852. * 
  853. * @uses current_user_can() Checks user capabilities given string 
  854. * @uses delete_post_thumbnail() Deletes post thumbnail given thumbnail id 
  855. * @uses set_post_thumbnail() Sets post thumbnail given post_id and thumbnail_id 
  856. * @uses wpsc_the_product_thumbnail() Returns URL to the product thumbnail 
  857. * 
  858. * @return array $response Includes the thumbnail URL and success bool value 
  859. */ 
  860. function _wpsc_ajax_set_variation_product_thumbnail() { 
  861. $response = array( 
  862. 'success' => false 
  863. ); 
  864.  
  865. $post_ID = intval( $_POST['post_id'] ); 
  866. if ( current_user_can( 'edit_post', $post_ID ) ) { 
  867. $thumbnail_id = intval( $_POST['thumbnail_id'] ); 
  868.  
  869. if ( $thumbnail_id == '-1' ) 
  870. delete_post_thumbnail( $post_ID ); 
  871.  
  872. set_post_thumbnail( $post_ID, $thumbnail_id ); 
  873.  
  874. $thumbnail = wpsc_the_product_thumbnail( 50, 50, $post_ID, '' ); 
  875. if ( ! $thumbnail ) 
  876. $thumbnail = WPSC_CORE_IMAGES_URL . '/no-image-uploaded.gif'; 
  877. $response['src'] = $thumbnail; 
  878. $response['success'] = true; 
  879.  
  880. echo json_encode( $response ); 
  881. exit; 
  882. add_action( 'wp_ajax_wpsc_set_variation_product_thumbnail', '_wpsc_ajax_set_variation_product_thumbnail' ); 
.