WCML_Custom_Prices

The WooCommerce Multilingual WCML Custom Prices class.

Defined (1)

The class is defined in the following location(s).

/inc/currencies/class-wcml-custom-prices.php  
  1. class WCML_Custom_Prices{ 
  2.  
  3. private $woocommerce_wpml; 
  4.  
  5. public function __construct( &$woocommerce_wpml ) { 
  6. add_filter( 'init', array( $this, 'custom_prices_init' ) ); 
  7. $this->woocommerce_wpml = $woocommerce_wpml; 
  8.  
  9. public function custom_prices_init() { 
  10. if ( is_admin() ) { 
  11. add_action( 'woocommerce_variation_options', array($this, 'add_individual_variation_nonce'), 10, 3 ); 
  12.  
  13. //custom prices for different currencies for products/variations [BACKEND] 
  14. add_action( 'woocommerce_product_options_pricing', array($this, 'woocommerce_product_options_custom_pricing') ); 
  15. add_action( 'woocommerce_product_after_variable_attributes', array($this, 'woocommerce_product_after_variable_attributes_custom_pricing'), 10, 3 ); 
  16.  
  17.  
  18. add_action( 'woocommerce_variation_is_visible', array( $this, 'filter_product_variations_with_custom_prices' ), 10, 2 ); 
  19.  
  20.  
  21. add_filter( 'loop_shop_post_in', array( $this, 'filter_products_with_custom_prices' ), 100 ); 
  22.  
  23.  
  24. public function add_individual_variation_nonce($loop, $variation_data, $variation) { 
  25.  
  26. wp_nonce_field('wcml_save_custom_prices_variation_' . $variation->ID, '_wcml_custom_prices_variation_' . $variation->ID . '_nonce'); 
  27.  
  28.  
  29. public function get_product_custom_prices($product_id, $currency = false) { 
  30. global $wpdb, $sitepress; 
  31.  
  32. if( empty( $currency ) ) { 
  33. $currency = $this->woocommerce_wpml->multi_currency->get_client_currency(); 
  34.  
  35. if( get_option('woocommerce_currency') == $currency ) { 
  36. return false; 
  37.  
  38. $original_product_id = $product_id; 
  39. $post_type = get_post_type($product_id); 
  40. $product_translations = $sitepress->get_element_translations($sitepress->get_element_trid($product_id, 'post_'.$post_type), 'post_'.$post_type); 
  41. foreach($product_translations as $translation) { 
  42. if( $translation->original ) { 
  43. $original_product_id = $translation->element_id; 
  44. break; 
  45.  
  46. $product_meta = get_post_custom($original_product_id); 
  47.  
  48. $custom_prices = false; 
  49.  
  50. if(!empty($product_meta['_wcml_custom_prices_status'][0])) { 
  51.  
  52. $prices_keys = array( 
  53. '_price', '_regular_price', '_sale_price',  
  54. '_min_variation_price', '_max_variation_price',  
  55. '_min_variation_regular_price', '_max_variation_regular_price',  
  56. '_min_variation_sale_price', '_max_variation_sale_price'); 
  57.  
  58. foreach($prices_keys as $key) { 
  59.  
  60. if(!empty($product_meta[$key . '_' . $currency][0])) { 
  61. $custom_prices[$key] = $product_meta[$key . '_' . $currency][0]; 
  62.  
  63.  
  64.  
  65. if(!isset($custom_prices['_price'])) return false; 
  66.  
  67. $current__price_value = $custom_prices['_price']; 
  68.  
  69. // update sale price 
  70. if(!empty($custom_prices['_sale_price'])) { 
  71.  
  72. if(!empty($product_meta['_wcml_schedule_' . $currency][0])) { 
  73. // custom dates 
  74. if(!empty($product_meta['_sale_price_dates_from_' . $currency][0]) && !empty($product_meta['_sale_price_dates_to_' . $currency][0])) { 
  75. if(current_time('timestamp') > $product_meta['_sale_price_dates_from_' . $currency][0] && current_time('timestamp') < $product_meta['_sale_price_dates_to_' . $currency][0]) { 
  76. $custom_prices['_price'] = $custom_prices['_sale_price']; 
  77. }else{ 
  78. $custom_prices['_price'] = $custom_prices['_regular_price']; 
  79. }else{ 
  80. $custom_prices['_price'] = $custom_prices['_sale_price']; 
  81.  
  82. }else{ 
  83. // inherit 
  84. if(!empty($product_meta['_sale_price_dates_from'][0]) && !empty($product_meta['_sale_price_dates_to'][0])) { 
  85. if(current_time('timestamp') > $product_meta['_sale_price_dates_from'][0] && current_time('timestamp') < $product_meta['_sale_price_dates_to'][0]) { 
  86. $custom_prices['_price'] = $custom_prices['_sale_price']; 
  87. }else{ 
  88. $custom_prices['_price'] = $custom_prices['_regular_price']; 
  89. }else{ 
  90. $custom_prices['_price'] = $custom_prices['_sale_price']; 
  91.  
  92.  
  93. if($custom_prices['_price'] != $current__price_value) { 
  94. update_post_meta($product_id, '_price_' . $currency, $custom_prices['_price']); 
  95.  
  96. // detemine min/max variation prices 
  97. if(!empty($product_meta['_min_variation_price'])) { 
  98.  
  99. static $product_min_max_prices = array(); 
  100.  
  101. if(empty($product_min_max_prices[$product_id])) { 
  102.  
  103. // get variation ids 
  104. $variation_ids = $wpdb->get_col($wpdb->prepare("SELECT ID FROM {$wpdb->posts} WHERE post_parent = %d", $product_id)); 
  105.  
  106. // variations with custom prices 
  107. $res = $wpdb->get_results($wpdb->prepare("SELECT post_id, meta_value FROM {$wpdb->postmeta} WHERE post_id IN(%s) AND meta_key='_wcml_custom_prices_status'", join(', ', $variation_ids))); 
  108. foreach($res as $row) { 
  109. $custom_prices_enabled[$row->post_id] = $row->meta_value; 
  110.  
  111. // REGULAR PRICES 
  112. // get custom prices 
  113. $res = $wpdb->get_results($wpdb->prepare("SELECT post_id, meta_value FROM {$wpdb->postmeta} WHERE post_id IN(%s) AND meta_key='_regular_price_" . $currency . "'", join(', ', $variation_ids))); 
  114. foreach($res as $row) { 
  115. $regular_prices[$row->post_id] = $row->meta_value; 
  116.  
  117. // get default prices (default currency) 
  118. $res = $wpdb->get_results($wpdb->prepare("SELECT post_id, meta_value FROM {$wpdb->postmeta} WHERE post_id IN(%s) AND meta_key='_regular_price'", join(', ', $variation_ids))); 
  119. foreach($res as $row) { 
  120. $default_regular_prices[$row->post_id] = $row->meta_value; 
  121.  
  122. // include the dynamic prices 
  123. foreach($variation_ids as $vid) { 
  124. if(empty($regular_prices[$vid]) && isset($default_regular_prices[$vid])) { 
  125. $regular_prices[$vid] = apply_filters('wcml_raw_price_amount', $default_regular_prices[$vid] ); 
  126.  
  127. // SALE PRICES 
  128. // get custom prices 
  129. $res = $wpdb->get_results($wpdb->prepare("SELECT post_id, meta_value FROM {$wpdb->postmeta} WHERE post_id IN(%s) AND meta_key=%s", join(', ', $variation_ids), '_sale_price_'.$currency)); 
  130. foreach($res as $row) { 
  131. $custom_sale_prices[$row->post_id] = $row->meta_value; 
  132.  
  133. // get default prices (default currency) 
  134. $res = $wpdb->get_results($wpdb->prepare("SELECT post_id, meta_value FROM {$wpdb->postmeta} WHERE post_id IN(%s) AND meta_key='_sale_price' AND meta_value <> ''", join(', ', $variation_ids))); 
  135. foreach($res as $row) { 
  136. $default_sale_prices[$row->post_id] = $row->meta_value; 
  137.  
  138. // include the dynamic prices 
  139. foreach($variation_ids as $vid) { 
  140. if(empty($sale_prices[$vid]) && isset($default_sale_prices[$vid])) { 
  141. $sale_prices[$vid] = apply_filters('wcml_raw_price_amount', $default_sale_prices[$vid]); 
  142.  
  143.  
  144. // PRICES 
  145. // get custom prices 
  146. $res = $wpdb->get_results($wpdb->prepare("SELECT post_id, meta_value FROM {$wpdb->postmeta} WHERE post_id IN(%s) AND meta_key=%s", join(', ', $variation_ids), '_price_'.$currency)); 
  147. foreach($res as $row) { 
  148. $custom_prices_prices[$row->post_id] = $row->meta_value; 
  149.  
  150. // get default prices (default currency) 
  151. $res = $wpdb->get_results($wpdb->prepare("SELECT post_id, meta_value FROM {$wpdb->postmeta} WHERE post_id IN(%s) AND meta_key='_price'", join(', ', $variation_ids))); 
  152. foreach($res as $row) { 
  153. $default_prices[$row->post_id] = $row->meta_value; 
  154.  
  155. // include the dynamic prices 
  156. foreach($variation_ids as $vid) { 
  157. if(empty($custom_prices_prices[$vid]) && isset($default_prices[$vid])) { 
  158. $prices[$vid] = apply_filters('wcml_raw_price_amount', $default_prices[$vid]); 
  159.  
  160. if(!empty($regular_prices)) { 
  161. $product_min_max_prices[$product_id]['_min_variation_regular_price'] = min($regular_prices); 
  162. $product_min_max_prices[$product_id]['_max_variation_regular_price'] = max($regular_prices); 
  163.  
  164. if(!empty($sale_prices)) { 
  165. $product_min_max_prices[$product_id]['_min_variation_sale_price'] = min($sale_prices); 
  166. $product_min_max_prices[$product_id]['_max_variation_sale_price'] = max($sale_prices); 
  167.  
  168. if(!empty($prices)) { 
  169. $product_min_max_prices[$product_id]['_min_variation_price'] = min($prices); 
  170. $product_min_max_prices[$product_id]['_max_variation_price'] = max($prices); 
  171.  
  172.  
  173.  
  174. if(isset($product_min_max_prices[$product_id]['_min_variation_regular_price'])) { 
  175. $custom_prices['_min_variation_regular_price'] = $product_min_max_prices[$product_id]['_min_variation_regular_price']; 
  176. if(isset($product_min_max_prices[$product_id]['_max_variation_regular_price'])) { 
  177. $custom_prices['_max_variation_regular_price'] = $product_min_max_prices[$product_id]['_max_variation_regular_price']; 
  178.  
  179. if(isset($product_min_max_prices[$product_id]['_min_variation_sale_price'])) { 
  180. $custom_prices['_min_variation_sale_price'] = $product_min_max_prices[$product_id]['_min_variation_sale_price']; 
  181. if(isset($product_min_max_prices[$product_id]['_max_variation_sale_price'])) { 
  182. $custom_prices['_max_variation_sale_price'] = $product_min_max_prices[$product_id]['_max_variation_sale_price']; 
  183.  
  184. if(isset($product_min_max_prices[$product_id]['_min_variation_price'])) { 
  185. $custom_prices['_min_variation_price'] = $product_min_max_prices[$product_id]['_min_variation_price']; 
  186. if(isset($product_min_max_prices[$product_id]['_max_variation_price'])) { 
  187. $custom_prices['_max_variation_price'] = $product_min_max_prices[$product_id]['_max_variation_price']; 
  188.  
  189.  
  190. $custom_prices = apply_filters( 'wcml_product_custom_prices', $custom_prices, $product_id, $currency ); 
  191.  
  192. return $custom_prices; 
  193.  
  194. public function woocommerce_product_options_custom_pricing() { 
  195. global $pagenow; 
  196.  
  197. $this->load_custom_prices_js_css(); 
  198.  
  199. if( ( isset($_GET['post'] ) && ( get_post_type($_GET['post']) != 'product' || !$this->woocommerce_wpml->products->is_original_product( $_GET['post'] ) ) ) || 
  200. ( isset($_GET['post_type'] ) && $_GET['post_type'] == 'product' && isset( $_GET['source_lang'] ) ) ) { 
  201. return; 
  202.  
  203. $product_id = 'new'; 
  204.  
  205. if($pagenow == 'post.php' && isset($_GET['post']) && get_post_type($_GET['post']) == 'product') { 
  206. $product_id = $_GET['post']; 
  207.  
  208. $this->custom_pricing_output($product_id); 
  209.  
  210. do_action( 'wcml_after_custom_prices_block', $product_id ); 
  211.  
  212. wp_nonce_field('wcml_save_custom_prices', '_wcml_custom_prices_nonce'); 
  213.  
  214.  
  215. public function woocommerce_product_after_variable_attributes_custom_pricing($loop, $variation_data, $variation) { 
  216.  
  217. if( $this->woocommerce_wpml->products->is_original_product( $variation->post_parent ) ) { 
  218.  
  219. echo '<tr><td>'; 
  220. $this->custom_pricing_output( $variation->ID ); 
  221. echo '</td></tr>'; 
  222.  
  223.  
  224.  
  225. private function load_custom_prices_js_css() { 
  226. wp_register_style( 'wpml-wcml-prices', WCML_PLUGIN_URL . '/res/css/wcml-prices.css', null, WCML_VERSION ); 
  227. wp_register_script( 'wcml-tm-scripts-prices', WCML_PLUGIN_URL . '/res/js/prices' . WCML_JS_MIN . '.js', array( 'jquery' ), WCML_VERSION ); 
  228.  
  229. wp_enqueue_style('wpml-wcml-prices'); 
  230. wp_enqueue_script('wcml-tm-scripts-prices'); 
  231.  
  232. private function custom_pricing_output( $post_id = false) { 
  233.  
  234. $custom_prices_ui = new WCML_Custom_Prices_UI( $this->woocommerce_wpml, $post_id ); 
  235. $custom_prices_ui->show(); 
  236.  
  237.  
  238. //set variations without custom prices to not visible when "Show only products with custom prices in secondary currencies" is enabled 
  239. public function filter_product_variations_with_custom_prices( $is_visible, $variation_id ) { 
  240.  
  241. if( is_product() && $this->woocommerce_wpml->settings['enable_multi_currency'] == WCML_MULTI_CURRENCIES_INDEPENDENT && 
  242. isset($this->woocommerce_wpml->settings['display_custom_prices']) && 
  243. $this->woocommerce_wpml->settings['display_custom_prices'] ) { 
  244.  
  245. $orig_child_id = $this->woocommerce_wpml->products->get_original_product_id( $variation_id ); 
  246.  
  247. if( !get_post_meta( $orig_child_id, '_wcml_custom_prices_status', true ) ) { 
  248. return false; 
  249.  
  250. return $is_visible; 
  251.  
  252. // display products with custom prices only if enabled "Show only products with custom prices in secondary currencies" option on settings page 
  253. public function filter_products_with_custom_prices( $filtered_posts ) { 
  254. global $wpdb; 
  255.  
  256. if( $this->woocommerce_wpml->settings[ 'enable_multi_currency' ] == WCML_MULTI_CURRENCIES_INDEPENDENT && 
  257. isset( $this->woocommerce_wpml->settings[ 'display_custom_prices' ] ) && 
  258. $this->woocommerce_wpml->settings[ 'display_custom_prices' ] ) { 
  259.  
  260. $client_currency = $this->woocommerce_wpml->multi_currency->get_client_currency(); 
  261. $woocommerce_currency = get_option( 'woocommerce_currency' ); 
  262.  
  263. if( $client_currency == $woocommerce_currency ) { 
  264. return $filtered_posts; 
  265. $matched_products = array(); 
  266. $matched_products_query = $wpdb->get_results( " 
  267. SELECT DISTINCT ID, post_parent, post_type FROM {$wpdb->posts} 
  268. INNER JOIN {$wpdb->postmeta} ON ID = post_id 
  269. WHERE post_type IN ( 'product', 'product_variation' ) AND post_status = 'publish' AND meta_key = '_wcml_custom_prices_status' AND meta_value = 1 
  270. ", OBJECT_K ); 
  271.  
  272. if ( $matched_products_query ) { 
  273. remove_filter( 'get_post_metadata', array( $this->woocommerce_wpml->multi_currency->prices, 'product_price_filter' ), 10, 4); 
  274. foreach ( $matched_products_query as $product ) { 
  275. if( !get_post_meta( $product->ID, '_price_'.$client_currency, true ) ) continue; 
  276. if ( $product->post_type == 'product' ) 
  277. $matched_products[] = apply_filters( 'translate_object_id', $product->ID, 'product', true ); 
  278. if ( $product->post_parent > 0 && ! in_array( $product->post_parent, $matched_products ) ) 
  279. $matched_products[] = apply_filters( 'translate_object_id', $product->post_parent, get_post_type( $product->post_parent ), true ); 
  280. add_filter('get_post_metadata', array( $this->woocommerce_wpml->multi_currency->prices, 'product_price_filter' ), 10, 4); 
  281.  
  282. // Filter the id's 
  283. if ( sizeof( $filtered_posts ) == 0) { 
  284. $filtered_posts = $matched_products; 
  285. $filtered_posts[] = 0; 
  286. } else { 
  287. $filtered_posts = array_intersect( $filtered_posts, $matched_products ); 
  288. $filtered_posts[] = 0; 
  289.  
  290. return $filtered_posts; 
  291.  
  292. public function save_custom_prices( $post_id ) { 
  293. $nonce = filter_input( INPUT_POST, '_wcml_custom_prices_nonce', FILTER_SANITIZE_FULL_SPECIAL_CHARS ); 
  294.  
  295. if( isset( $_POST[ '_wcml_custom_prices' ] ) && isset( $nonce ) && wp_verify_nonce( $nonce, 'wcml_save_custom_prices' ) && !$this->woocommerce_wpml->products->is_variable_product( $post_id ) ) { 
  296. if( isset( $_POST[ '_wcml_custom_prices' ][ $post_id ] ) || isset( $_POST[ '_wcml_custom_prices' ][ 'new' ] ) ) { 
  297. $wcml_custom_prices_option = isset( $_POST[ '_wcml_custom_prices' ][ $post_id ] ) ? $_POST[ '_wcml_custom_prices' ][ $post_id ] : $_POST[ '_wcml_custom_prices' ][ 'new' ]; 
  298. }else{ 
  299. $current_option = get_post_meta( $post_id, '_wcml_custom_prices_status', true ); 
  300. $wcml_custom_prices_option = $current_option ? $current_option : 0; 
  301. update_post_meta( $post_id, '_wcml_custom_prices_status', $wcml_custom_prices_option ); 
  302.  
  303. if( $wcml_custom_prices_option == 1) { 
  304. $currencies = $this->woocommerce_wpml->multi_currency->get_currencies(); 
  305. foreach( $currencies as $code => $currency ) { 
  306. $sale_price = wc_format_decimal( $_POST[ '_custom_sale_price' ][ $code ] ); 
  307. $regular_price = wc_format_decimal( $_POST[ '_custom_regular_price' ][ $code ] ); 
  308. $date_from = isset( $_POST[ '_custom_sale_price_dates_from' ][ $code ] ) ? strtotime( $_POST[ '_custom_sale_price_dates_from' ][ $code ] ) : ''; 
  309. $date_to = isset( $_POST[ '_custom_sale_price_dates_to' ][ $code ] ) ? strtotime( $_POST[ '_custom_sale_price_dates_to' ][ $code ] ) : ''; 
  310. $schedule = $_POST[ '_wcml_schedule' ][ $code ]; 
  311.  
  312. $custom_prices = apply_filters( 'wcml_update_custom_prices_values',  
  313. array( '_regular_price' => $regular_price,  
  314. '_sale_price' => $sale_price,  
  315. '_wcml_schedule' => $schedule,  
  316. '_sale_price_dates_from' => $date_from,  
  317. '_sale_price_dates_to' => $date_to ),  
  318. $code 
  319. ); 
  320. $product_price = $this->update_custom_prices( $post_id, $custom_prices , $code ); 
  321.  
  322. do_action( 'wcml_after_save_custom_prices', $post_id, $product_price, $custom_prices, $code ); 
  323.  
  324. public function update_custom_prices( $post_id, $custom_prices, $code ) { 
  325. $price = ''; 
  326.  
  327. // initialization 
  328. $keys = array( 
  329. '_sale_price_dates_to', '_sale_price_dates_from',  
  330. '_sale_price', '_sale_price_dates_to', '_sale_price_dates_from',  
  331.  
  332. ); 
  333. foreach( $keys as $key ) { 
  334. if( !isset( $custom_prices[$key] ) ) { $custom_prices[$key] = ''; } 
  335.  
  336. foreach( $custom_prices as $custom_price_key => $custom_price_value ) { 
  337. update_post_meta( $post_id, $custom_price_key.'_'.$code, $custom_price_value ); 
  338. if ( $custom_prices[ '_sale_price_dates_to' ] && ! $custom_prices[ '_sale_price_dates_from' ] ) { 
  339. update_post_meta($post_id, '_sale_price_dates_from_' . $code, strtotime( 'NOW', current_time( 'timestamp' ) ) ); 
  340. // Update price if on sale 
  341. if ( $custom_prices[ '_sale_price' ] != '' && $custom_prices[ '_sale_price_dates_to' ] == '' && $custom_prices[ '_sale_price_dates_from' ] == '' ) { 
  342. $price = stripslashes( $custom_prices[ '_sale_price' ] ); 
  343. update_post_meta( $post_id, '_price_'.$code, stripslashes( $custom_prices[ '_sale_price' ] ) ); 
  344. }else{ 
  345. $price = stripslashes( $custom_prices[ '_regular_price' ] ); 
  346. update_post_meta( $post_id, '_price_'.$code, stripslashes( $custom_prices[ '_regular_price' ] ) ); 
  347.  
  348. if ( $custom_prices[ '_sale_price' ] != '' && $custom_prices[ '_sale_price_dates_from' ] < strtotime( 'NOW', current_time( 'timestamp' ) ) ) { 
  349. update_post_meta( $post_id, '_price_'.$code, stripslashes( $custom_prices[ '_sale_price' ] ) ); 
  350. $price = stripslashes( $custom_prices[ '_sale_price' ] ); 
  351.  
  352. if ( $custom_prices[ '_sale_price_dates_to' ] && $custom_prices[ '_sale_price_dates_to' ] < strtotime( 'NOW', current_time( 'timestamp' ) ) ) { 
  353. update_post_meta( $post_id, '_price_'.$code, stripslashes( $custom_prices[ '_regular_price' ] ) ); 
  354. $price = stripslashes( $custom_prices[ '_regular_price' ] ); 
  355. update_post_meta( $post_id, '_sale_price_dates_from_'.$code, '' ); 
  356. update_post_meta( $post_id, '_sale_price_dates_to_'.$code, '' ); 
  357.  
  358. return $price; 
  359.  
  360. public function sync_product_variations_custom_prices( $product_id ) { 
  361.  
  362. if( isset( $_POST[ '_wcml_custom_prices' ][ $product_id ] ) ) { 
  363.  
  364. //save custom prices for variation 
  365. $nonce = filter_input( INPUT_POST, '_wcml_custom_prices_variation_' . $product_id . '_nonce', FILTER_SANITIZE_FULL_SPECIAL_CHARS ); 
  366. if( isset( $_POST[ '_wcml_custom_prices' ][ $product_id ] ) && isset( $nonce ) && wp_verify_nonce( $nonce, 'wcml_save_custom_prices_variation_' . $product_id ) ) { 
  367. update_post_meta( $product_id, '_wcml_custom_prices_status', $_POST[ '_wcml_custom_prices' ][ $product_id ] ); 
  368. $currencies = $this->woocommerce_wpml->multi_currency->get_currencies(); 
  369.  
  370. if( $_POST[ '_wcml_custom_prices' ][ $product_id ] == 1 ) { 
  371. foreach( $currencies as $code => $currency ) { 
  372. $sale_price = wc_format_decimal( $_POST[ '_custom_variation_sale_price' ][ $code ][ $product_id ] ); 
  373. $regular_price = wc_format_decimal( $_POST[ '_custom_variation_regular_price' ][ $code ][ $product_id ] ); 
  374. $date_from = strtotime( $_POST[ '_custom_variation_sale_price_dates_from' ][ $code ][ $product_id ] ); 
  375. $date_to = strtotime( $_POST[ '_custom_variation_sale_price_dates_to' ][ $code ][ $product_id ] ); 
  376. $schedule = $_POST[ '_wcml_schedule' ][ $code ][ $product_id ]; 
  377. $custom_prices = apply_filters( 'wcml_update_custom_prices_values',  
  378. array( '_regular_price' => $regular_price,  
  379. '_sale_price' => $sale_price,  
  380. '_wcml_schedule_' => $schedule,  
  381. '_sale_price_dates_from' => $date_from,  
  382. '_sale_price_dates_to' => $date_to ),  
  383. $code,  
  384. $product_id 
  385. ); 
  386. $price = $this->update_custom_prices( $product_id, $custom_prices, $code ); 
  387.