/inc/currencies/class-wcml-custom-prices.php

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