WCML_Composite_Products

The WooCommerce Multilingual WCML Composite Products class.

Defined (1)

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

/compatibility/class-wcml-composite-products.php  
  1. class WCML_Composite_Products extends WCML_Compatibility_Helper{ 
  2.  
  3. /** 
  4. * @var SitePress 
  5. */ 
  6. public $sitepress; 
  7.  
  8. /** 
  9. * @var woocommerce_wpml 
  10. */ 
  11. public $woocommerce_wpml; 
  12.  
  13. private $tp; 
  14.  
  15. function __construct( &$sitepress, &$woocommerce_wpml ) { 
  16. $this->sitepress = $sitepress; 
  17. $this->woocommerce_wpml = $woocommerce_wpml; 
  18.  
  19. add_filter( 'woocommerce_composite_component_default_option', array($this, 'woocommerce_composite_component_default_option'), 10, 3 ); 
  20. add_filter( 'wcml_cart_contents', array($this, 'wpml_composites_compat'), 11, 4 ); 
  21. add_filter( 'woocommerce_composite_component_options_query_args', array($this, 'wpml_composites_transients_cache_per_language'), 10, 3 ); 
  22. add_action( 'wcml_before_sync_product', array( $this, 'sync_composite_data_across_translations'), 10, 2 ); 
  23.  
  24. if( is_admin() ) {  
  25.  
  26. add_action( 'wcml_gui_additional_box_html', array( $this, 'custom_box_html' ), 10, 3 ); 
  27. add_filter( 'wcml_gui_additional_box_data', array( $this, 'custom_box_html_data' ), 10, 4 ); 
  28. add_action( 'wcml_update_extra_fields', array( $this, 'components_update' ), 10, 4 ); 
  29. add_filter( 'woocommerce_json_search_found_products', array( $this, 'woocommerce_json_search_found_products' ) ); 
  30.  
  31. $this->tp = new WPML_Element_Translation_Package(); 
  32.  
  33. add_filter( 'wpml_tm_translation_job_data', array( $this, 'append_composite_data_translation_package' ), 10, 2 ); 
  34. add_action( 'wpml_translation_job_saved', array( $this, 'save_composite_data_translation' ), 10, 3 ); 
  35. //lock fields on translations pages 
  36. add_filter( 'wcml_js_lock_fields_input_names', array( $this, 'wcml_js_lock_fields_input_names' ) ); 
  37. add_filter( 'wcml_js_lock_fields_ids', array( $this, 'wcml_js_lock_fields_ids' ) ); 
  38. add_filter( 'wcml_after_load_lock_fields_js', array( $this, 'localize_lock_fields_js' ) ); 
  39. add_action( 'init', array( $this, 'load_assets' ) ); 
  40.  
  41. add_action( 'wcml_after_save_custom_prices', array( $this, 'update_composite_custom_prices' ), 10, 4 ); 
  42. }else{ 
  43. add_filter( 'get_post_metadata', array( $this, 'filter_composite_product_cost' ), 10, 4 ); 
  44.  
  45.  
  46. function woocommerce_composite_component_default_option($selected_value, $component_id, $object) { 
  47.  
  48. if( !empty( $selected_value ) ) 
  49. $selected_value = apply_filters( 'wpml_object_id', $selected_value, 'product', true ); 
  50.  
  51.  
  52. return $selected_value; 
  53.  
  54. function wpml_composites_compat( $new_cart_data, $cart_contents, $key, $new_key ) { 
  55.  
  56. if ( isset( $cart_contents[ $key ][ 'composite_children' ] ) || isset( $cart_contents[ $key ][ 'composite_parent' ] ) ) { 
  57.  
  58. $buff = $new_cart_data[ $new_key ]; 
  59.  
  60. unset( $new_cart_data[ $new_key ] ); 
  61.  
  62. $new_cart_data[ $key ] = $buff; 
  63.  
  64. return $new_cart_data; 
  65.  
  66. function wpml_composites_transients_cache_per_language( $args, $query_args, $component_data ) { 
  67.  
  68. $args[ 'wpml_lang' ] = apply_filters( 'wpml_current_language', NULL ); 
  69.  
  70. return $args; 
  71.  
  72. function sync_composite_data_across_translations( $original_product_id, $current_product_id ) { 
  73.  
  74. if( $this->get_product_type( $original_product_id ) == 'composite' ) { 
  75.  
  76. $composite_data = $this->get_composite_data( $original_product_id ); 
  77.  
  78. $product_trid = $this->sitepress->get_element_trid( $original_product_id, 'post_product' ); 
  79. $product_translations = $this->sitepress->get_element_translations( $product_trid, 'post_product' ); 
  80.  
  81. foreach ( $product_translations as $product_translation ) { 
  82.  
  83. if ( empty($product_translation->original) ) { 
  84.  
  85. $translated_composite_data = $this->get_composite_data( $product_translation->element_id ); 
  86.  
  87. foreach ( $composite_data as $component_id => $component ) { 
  88.  
  89. if( isset( $translated_composite_data[$component_id]['title'] ) ) { 
  90. $composite_data[$component_id]['title'] = $translated_composite_data[$component_id]['title']; 
  91.  
  92. if( isset( $translated_composite_data[$component_id]['description'] ) ) { 
  93. $composite_data[$component_id]['description'] = $translated_composite_data[$component_id]['description']; 
  94.  
  95. if ( $component['query_type'] == 'product_ids' ) { 
  96.  
  97. foreach ( $component['assigned_ids'] as $idx => $assigned_id ) { 
  98. $composite_data[$component_id]['assigned_ids'][$idx] = 
  99. apply_filters( 'translate_object_id', $assigned_id, 'product', true, $product_translation->language_code ); 
  100.  
  101. } elseif( $component['query_type'] == 'category_ids' ) { 
  102.  
  103. foreach ( $component['assigned_category_ids'] as $idx => $assigned_id ) { 
  104. $composite_data[$component_id]['assigned_category_ids'][$idx] = 
  105. apply_filters( 'translate_object_id', $assigned_id, 'product_cat', true, $product_translation->language_code ); 
  106.  
  107.  
  108.  
  109.  
  110. update_post_meta( $product_translation->element_id, '_bto_data', $composite_data ); 
  111.  
  112.  
  113.  
  114.  
  115. function custom_box_html( $obj, $product_id, $data ) { 
  116.  
  117. if( $this->get_product_type( $product_id ) == 'composite' ) { 
  118.  
  119. $composite_data = $this->get_composite_data( $product_id ); 
  120.  
  121. $composite_section = new WPML_Editor_UI_Field_Section( __( 'Composite Products ( Components )', 'woocommerce-multilingual' ) ); 
  122. end( $composite_data ); 
  123. $last_key = key( $composite_data ); 
  124. $divider = true; 
  125. foreach( $composite_data as $component_id => $component ) { 
  126. if( $component_id == $last_key ) { 
  127. $divider = false; 
  128. $group = new WPML_Editor_UI_Field_Group( '', $divider ); 
  129. $composite_field = new WPML_Editor_UI_Single_Line_Field( 'composite_'.$component_id.'_title', __( 'Name', 'woocommerce-multilingual' ), $data, false ); 
  130. $group->add_field( $composite_field ); 
  131. $composite_field = new WPML_Editor_UI_Single_Line_Field( 'composite_'.$component_id.'_description' , __( 'Description', 'woocommerce-multilingual' ), $data, false ); 
  132. $group->add_field( $composite_field ); 
  133. $composite_section->add_field( $group ); 
  134.  
  135.  
  136. if( $composite_data ) { 
  137. $obj->add_field( $composite_section ); 
  138.  
  139. $composite_scenarios_meta = $this->get_composite_scenarios_meta( $product_id ); 
  140. if( $composite_scenarios_meta ) { 
  141.  
  142. $composite_scenarios = new WPML_Editor_UI_Field_Section( __( 'Composite Products ( Scenarios )', 'woocommerce-multilingual' ) ); 
  143. end( $composite_scenarios_meta ); 
  144. $last_key = key( $composite_scenarios_meta ); 
  145. $divider = true; 
  146. foreach( $composite_scenarios_meta as $scenario_key => $scenario_meta ) { 
  147. if( $scenario_key == $last_key ) { 
  148. $divider = false; 
  149. $group = new WPML_Editor_UI_Field_Group( '', $divider ); 
  150. $composite_scenario_field = new WPML_Editor_UI_Single_Line_Field( 'composite_scenario_'.$scenario_key.'_title', __( 'Name', 'woocommerce-multilingual' ), $data, false ); 
  151. $group->add_field( $composite_scenario_field ); 
  152. $composite_scenario_field = new WPML_Editor_UI_Single_Line_Field( 'composite_scenario_'.$scenario_key.'_description' , __( 'Description', 'woocommerce-multilingual' ), $data, false ); 
  153. $group->add_field( $composite_scenario_field ); 
  154. $composite_scenarios->add_field( $group ); 
  155.  
  156.  
  157. $obj->add_field( $composite_scenarios ); 
  158.  
  159.  
  160.  
  161.  
  162. function custom_box_html_data( $data, $product_id, $translation, $lang ) { 
  163.  
  164. if( $this->get_product_type( $product_id ) == 'composite' ) { 
  165.  
  166. $composite_data = $this->get_composite_data( $product_id ); 
  167.  
  168. foreach( $composite_data as $component_id => $component ) { 
  169.  
  170. $data['composite_'.$component_id.'_title'] = array( 'original' => 
  171. isset( $composite_data[$component_id]['title'] ) ? $composite_data[$component_id]['title'] : '' ); 
  172.  
  173. $data['composite_'.$component_id.'_description'] = array( 'original' => 
  174. isset( $composite_data[$component_id]['description'] ) ? $composite_data[$component_id]['description'] : '' ); 
  175.  
  176.  
  177. $composite_scenarios_meta = $this->get_composite_scenarios_meta( $product_id ); 
  178. if( $composite_scenarios_meta ) { 
  179. foreach( $composite_scenarios_meta as $scenario_key => $scenario_meta ) { 
  180. $data[ 'composite_scenario_'.$scenario_key.'_title' ] = array( 
  181. 'original' => isset( $scenario_meta['title'] ) ? $scenario_meta['title'] : '',  
  182. 'translation' => '' 
  183. ); 
  184.  
  185. $data[ 'composite_scenario_'.$scenario_key.'_description' ] = array( 
  186. 'original' => isset( $scenario_meta['description'] ) ? $scenario_meta['description'] : '',  
  187. 'translation' => '' 
  188. ); 
  189.  
  190. if( $translation ) { 
  191. $translated_composite_data = $this->get_composite_data( $translation->ID ); 
  192.  
  193. foreach( $composite_data as $component_id => $component ) { 
  194.  
  195. $data['composite_'.$component_id.'_title'][ 'translation' ] = 
  196. isset( $translated_composite_data[$component_id]['title'] ) ? $translated_composite_data[$component_id]['title'] : ''; 
  197.  
  198. $data['composite_'.$component_id.'_description'][ 'translation' ] = 
  199. isset( $translated_composite_data[$component_id]['description'] ) ? $translated_composite_data[$component_id]['description'] : ''; 
  200.  
  201.  
  202. $translated_composite_scenarios_meta = $this->get_composite_scenarios_meta( $translation->ID ); 
  203. if( $translated_composite_scenarios_meta ) { 
  204. foreach( $translated_composite_scenarios_meta as $scenario_key => $translated_scenario_meta ) { 
  205. $data[ 'composite_scenario_'.$scenario_key.'_title' ][ 'translation' ] = 
  206. isset( $translated_scenario_meta['title'] ) ? $translated_scenario_meta['title'] : ''; 
  207.  
  208. $data[ 'composite_scenario_'.$scenario_key.'_description' ][ 'translation' ] = 
  209. isset( $translated_scenario_meta['description'] ) ? $translated_scenario_meta['description'] : ''; 
  210.  
  211.  
  212.  
  213. return $data; 
  214.  
  215. function components_update( $original_product_id, $product_id, $data, $language ) { 
  216.  
  217. $composite_data = $this->get_composite_data( $original_product_id ); 
  218.  
  219. foreach( $composite_data as $component_id => $component ) { 
  220.  
  221. if(!empty($data[ md5( 'composite_'.$component_id.'_title' ) ] ) ) { 
  222. $composite_data[$component_id]['title'] = $data[ md5( 'composite_'.$component_id.'_title' ) ]; 
  223.  
  224. if(!empty($data[ md5( 'composite_'.$component_id.'_description' ) ])) { 
  225. $composite_data[$component_id]['description'] = $data[ md5( 'composite_'.$component_id.'_description' ) ]; 
  226.  
  227. //sync product ids 
  228. if( $component[ 'query_type' ] == 'product_ids' ) { 
  229. foreach( $component[ 'assigned_ids' ] as $key => $assigned_id ) { 
  230. $assigned_id_current_language = apply_filters( 'translate_object_id', $assigned_id, get_post_type( $assigned_id ), false, $language ); 
  231. if( $assigned_id_current_language ) { 
  232. $composite_data[ $component_id ][ 'assigned_ids' ][ $key ] = $assigned_id_current_language; 
  233. //sync default 
  234. if( $component[ 'default_id' ] ) { 
  235. $trnsl_default_id = apply_filters( 'translate_object_id', $component[ 'default_id' ], get_post_type( $component[ 'default_id' ] ), false, $language ); 
  236. if( $trnsl_default_id ) { 
  237. $composite_data[ $component_id ][ 'default_id' ] = $trnsl_default_id; 
  238.  
  239. }elseif( $component[ 'query_type' ] == 'category_ids' ) { 
  240. foreach( $component[ 'assigned_category_ids' ] as $key => $assigned_id ) { 
  241. $trsl_term_id = apply_filters( 'translate_object_id', $assigned_id, 'product_cat', false, $language ); 
  242. if( $trsl_term_id ) { 
  243. $composite_data[ $component_id ][ 'assigned_category_ids' ][ $key ] = $trsl_term_id; 
  244. //sync default 
  245. if( $component[ 'default_id' ] ) { 
  246. $trnsl_default_id = apply_filters( 'translate_object_id', $component[ 'default_id' ], 'product_cat', false, $language ); 
  247. if( $trnsl_default_id ) { 
  248. $composite_data[ $component_id ][ 'default_id' ] = $trnsl_default_id; 
  249.  
  250. update_post_meta( $product_id, '_bto_data', $composite_data ); 
  251.  
  252. $composite_scenarios_meta = $this->get_composite_scenarios_meta( $original_product_id ); 
  253. if( $composite_scenarios_meta ) { 
  254. foreach( $composite_scenarios_meta as $scenario_key => $scenario_meta ) { 
  255. if( !empty( $data[ md5( 'composite_scenario_'.$scenario_key.'_title' ) ] ) ) { 
  256. $composite_scenarios_meta[ $scenario_key ][ 'title' ] = $data[ md5( 'composite_scenario_'.$scenario_key.'_title' ) ]; 
  257.  
  258. if( !empty( $data[ md5( 'composite_scenario_'.$scenario_key.'_description' ) ])) { 
  259. $composite_scenarios_meta[ $scenario_key ][ 'description' ] = $data[ md5( 'composite_scenario_'.$scenario_key.'_description' ) ]; 
  260.  
  261. //sync product ids 
  262. foreach( $scenario_meta[ 'component_data' ] as $compon_id => $component_data ) { 
  263. if( isset( $composite_data[ $compon_id ] ) && $composite_data[ $compon_id ][ 'query_type' ] == 'product_ids' ) { 
  264. foreach( $component_data as $key => $assigned_prod_id ) { 
  265. $trnsl_assigned_prod_id = apply_filters( 'translate_object_id', $assigned_prod_id, get_post_type( $assigned_prod_id ), false, $language ); 
  266. if( $trnsl_assigned_prod_id ) { 
  267. $composite_scenarios_meta[ $scenario_key ][ 'component_data' ][ $compon_id ][ $key ] = $trnsl_assigned_prod_id; 
  268. }elseif( isset( $composite_data[ $compon_id ] ) && $composite_data[ $compon_id ][ 'query_type' ] == 'category_ids' ) { 
  269. foreach( $component_data as $key => $assigned_cat_id ) { 
  270. $trslt_assigned_cat_id = apply_filters( 'translate_object_id', $assigned_cat_id, 'product_cat', false, $language ); 
  271. if( $trslt_assigned_cat_id ) { 
  272. $composite_scenarios_meta[ $scenario_key ][ 'component_data' ][ $compon_id ][ $key ] = $trslt_assigned_cat_id; 
  273.  
  274. update_post_meta( $product_id, '_bto_scenario_data', $composite_scenarios_meta ); 
  275.  
  276. return array( 
  277. 'components' => $composite_data,  
  278. 'scenarios' => $composite_scenarios_meta,  
  279. ); 
  280.  
  281. function append_composite_data_translation_package( $package, $post ) { 
  282.  
  283. if( $post->post_type == 'product' ) { 
  284.  
  285. $composite_data = get_post_meta( $post->ID, '_bto_data', true ); 
  286.  
  287. if( $composite_data ) { 
  288.  
  289. $fields = array( 'title', 'description' ); 
  290.  
  291. foreach( $composite_data as $component_id => $component ) { 
  292.  
  293. foreach( $fields as $field ) { 
  294. if ( !empty($component[$field]) ) { 
  295.  
  296. $package['contents']['wc_composite:' . $component_id . ':' . $field] = array( 
  297. 'translate' => 1,  
  298. 'data' => $this->tp->encode_field_data( $component[$field], 'base64' ),  
  299. 'format' => 'base64' 
  300. ); 
  301.  
  302.  
  303.  
  304.  
  305.  
  306. return $package; 
  307.  
  308.  
  309. function save_composite_data_translation( $post_id, $data, $job ) { 
  310.  
  311.  
  312. $translated_composite_data = array(); 
  313. foreach( $data as $value) { 
  314.  
  315. if( preg_match( '/wc_composite:([0-9]+):(.+)/', $value['field_type'], $matches ) ) { 
  316.  
  317. $component_id = $matches[1]; 
  318. $field = $matches[2]; 
  319.  
  320. $translated_composite_data[$component_id][$field] = $value['data']; 
  321.  
  322.  
  323.  
  324. if( $translated_composite_data ) { 
  325.  
  326. $composite_data = get_post_meta( $job->original_doc_id, '_bto_data', true ); 
  327.  
  328.  
  329. foreach ( $composite_data as $component_id => $component ) { 
  330.  
  331. if( isset( $translated_composite_data[$component_id]['title'] ) ) { 
  332. $composite_data[$component_id]['title'] = $translated_composite_data[$component_id]['title']; 
  333.  
  334. if( isset( $translated_composite_data[$component_id]['description'] ) ) { 
  335. $composite_data[$component_id]['description'] = $translated_composite_data[$component_id]['description']; 
  336.  
  337. if ( $component['query_type'] == 'product_ids' ) { 
  338.  
  339. foreach ( $component['assigned_ids'] as $idx => $assigned_id ) { 
  340. $composite_data[$component_id]['assigned_ids'][$idx] = 
  341. apply_filters( 'translate_object_id', $assigned_id, 'product', true, $job->language_code ); 
  342.  
  343. } elseif( $component['query_type'] == 'category_ids' ) { 
  344.  
  345. foreach ( $component['assigned_category_ids'] as $idx => $assigned_id ) { 
  346. $composite_data[$component_id]['assigned_category_ids'][$idx] = 
  347. apply_filters( 'translate_object_id', $assigned_id, 'product_cat', true, $job->language_code ); 
  348.  
  349.  
  350.  
  351.  
  352.  
  353. update_post_meta( $post_id, '_bto_data', $composite_data ); 
  354.  
  355.  
  356. function wcml_js_lock_fields_input_names( $names ) { 
  357.  
  358. $names[] = '_base_regular_price'; 
  359. $names[] = '_base_sale_price'; 
  360. $names[] = 'bto_style'; 
  361.  
  362. return $names; 
  363.  
  364. function wcml_js_lock_fields_ids( $names ) { 
  365.  
  366. $names[] = '_per_product_pricing_bto'; 
  367. $names[] = '_per_product_shipping_bto'; 
  368. $names[] = '_bto_hide_shop_price'; 
  369.  
  370. return $names; 
  371.  
  372. function localize_lock_fields_js() { 
  373. wp_localize_script( 'wcml-composite-js', 'lock_settings' , array( 'lock_fields' => 1 ) ); 
  374.  
  375. function load_assets( ) { 
  376. global $pagenow; 
  377.  
  378. if( ( $pagenow == 'post.php' && isset( $_GET[ 'post' ] ) && WooCommerce_Functions_Wrapper::get_product_type( $_GET[ 'post' ] ) === 'composite' ) || $pagenow == 'post-new.php' ) { 
  379. wp_register_script( 'wcml-composite-js', WCML_PLUGIN_URL . '/compatibility/res/js/wcml-composite.js', array( 'jquery' ), WCML_VERSION ); 
  380. wp_enqueue_script( 'wcml-composite-js' ); 
  381.  
  382.  
  383.  
  384. function woocommerce_json_search_found_products( $found_products ) { 
  385. global $wpml_post_translations; 
  386.  
  387. foreach( $found_products as $id => $product_name ) { 
  388. if( $wpml_post_translations->get_element_lang_code ( $id ) != $this->sitepress->get_current_language() ) { 
  389. unset( $found_products[ $id ] ); 
  390.  
  391. return $found_products; 
  392.  
  393. public function get_composite_scenarios_meta( $product_id ) { 
  394. return get_post_meta( $product_id, '_bto_scenario_data', true ); 
  395.  
  396. public function get_composite_data( $product_id ) { 
  397. return get_post_meta( $product_id, '_bto_data', true ); 
  398.  
  399.  
  400. function filter_composite_product_cost( $value, $object_id, $meta_key, $single ) { 
  401.  
  402. if ( in_array( $meta_key, array( 
  403. '_bto_base_regular_price',  
  404. '_bto_base_sale_price',  
  405. '_bto_base_price' 
  406. ) ) ) { 
  407.  
  408. if ( $this->woocommerce_wpml->settings['enable_multi_currency'] == WCML_MULTI_CURRENCIES_INDEPENDENT ) { 
  409.  
  410. $original_id = $this->woocommerce_wpml->products->get_original_product_id( $object_id ); 
  411.  
  412. $cost_status = get_post_meta( $original_id, '_wcml_custom_prices_status', true ); 
  413.  
  414. $currency = $this->woocommerce_wpml->multi_currency->get_client_currency(); 
  415.  
  416. if ( $currency == get_option( 'woocommerce_currency' ) ) { 
  417. return $value; 
  418.  
  419. $cost = get_post_meta( $original_id, $meta_key . '_' . $currency, true ); 
  420.  
  421. if ( $cost_status && !empty( $cost ) ) { 
  422.  
  423. return $cost; 
  424.  
  425. } else { 
  426.  
  427. remove_filter( 'get_post_metadata', array( $this, 'filter_composite_product_cost' ), 10, 4 ); 
  428.  
  429. $cost = get_post_meta( $original_id, $meta_key, true ); 
  430.  
  431. add_filter( 'get_post_metadata', array( $this, 'filter_composite_product_cost' ), 10, 4 ); 
  432.  
  433. if( $cost ) { 
  434.  
  435. $cost = $this->woocommerce_wpml->multi_currency->prices->convert_price_amount( $cost, $currency ); 
  436.  
  437. return $cost; 
  438.  
  439.  
  440.  
  441.  
  442. return $value; 
  443.  
  444. function update_composite_custom_prices( $product_id, $product_price, $custom_prices, $code ) { 
  445.  
  446. if( $this->get_product_type( $product_id ) == 'composite' ) { 
  447.  
  448. update_post_meta( $product_id, '_bto_base_regular_price'.'_'.$code, $custom_prices[ '_regular_price' ] ); 
  449. update_post_meta( $product_id, '_bto_base_sale_price'.'_'.$code, $custom_prices[ '_sale_price' ] ); 
  450. update_post_meta( $product_id, '_bto_base_price'.'_'.$code, $product_price ); 
  451.  
  452.  
  453.