WCML_Attributes

The WooCommerce Multilingual WCML Attributes class.

Defined (1)

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

/inc/class-wcml-attributes.php  
  1. class WCML_Attributes{ 
  2.  
  3. private $woocommerce_wpml; 
  4. private $sitepress; 
  5. private $wpdb; 
  6.  
  7. public function __construct( &$woocommerce_wpml, &$sitepress, &$wpdb ) { 
  8. $this->woocommerce_wpml = $woocommerce_wpml; 
  9. $this->sitepress = $sitepress; 
  10. $this->wpdb = $wpdb; 
  11.  
  12. add_action( 'init', array( $this, 'init' ) ); 
  13.  
  14. add_action( 'woocommerce_attribute_added', array( $this, 'set_attribute_readonly_config' ), 100, 2 ); 
  15. add_filter( 'wpml_translation_job_post_meta_value_translated', array($this, 'filter_product_attributes_for_translation'), 10, 2 ); 
  16. add_filter( 'woocommerce_dropdown_variation_attribute_options_args', array($this, 'filter_dropdown_variation_attribute_options_args') ); 
  17.  
  18. if( isset( $_POST['icl_ajx_action'] ) && $_POST['icl_ajx_action'] == 'icl_custom_tax_sync_options' ) { 
  19. $this->icl_custom_tax_sync_options(); 
  20.  
  21. add_action( 'woocommerce_before_attribute_delete', array( $this, 'refresh_taxonomy_translations_cache' ), 10, 3 ); 
  22.  
  23. if( ( defined('WC_VERSION') && version_compare( WC_VERSION , '3.0.0', '<' ) ) ) { 
  24. add_filter( 'woocommerce_get_product_attributes', array( $this, 'filter_adding_to_cart_product_attributes_names' ) ); 
  25. }else{ 
  26. add_filter( 'woocommerce_product_get_attributes', array( $this, 'filter_adding_to_cart_product_attributes_names' ) ); 
  27.  
  28.  
  29. public function init() { 
  30.  
  31. $is_attr_page = apply_filters( 'wcml_is_attributes_page', isset( $_GET[ 'page' ] ) && $_GET[ 'page' ] == 'product_attributes' && isset( $_GET[ 'post_type' ] ) && $_GET[ 'post_type' ] == 'product' ); 
  32.  
  33. if( $is_attr_page ) { 
  34.  
  35. add_action( 'admin_init', array( $this, 'not_translatable_html' ) ); 
  36.  
  37. if( isset( $_POST[ 'save_attribute' ] ) && isset( $_GET[ 'edit' ] ) ) { 
  38. $this->set_attribute_readonly_config( $_GET[ 'edit' ], $_POST ); 
  39.  
  40.  
  41. /** 
  42. * This creates the terms translation cache so the translations can be deleted via the 'delete_term' hook 
  43. * after the original term was deleted and getting the translations directly from the db is not possible 
  44. */ 
  45. public function refresh_taxonomy_translations_cache( $attribute_id, $attribute_name, $taxonomy ) { 
  46.  
  47. $terms = get_terms( $taxonomy, 'orderby=name&hide_empty=0' ); 
  48. foreach ( $terms as $term ) { 
  49. $trid = $this->sitepress->get_element_trid( $term->term_taxonomy_id, 'tax_' . $taxonomy ); 
  50.  
  51.  
  52. public function not_translatable_html() { 
  53. $attr_id = isset( $_GET[ 'edit' ] ) ? absint( $_GET[ 'edit' ] ) : false; 
  54.  
  55. $attr_is_tnaslt = new WCML_Not_Translatable_Attributes( $attr_id, $this->woocommerce_wpml ); 
  56. $attr_is_tnaslt->show(); 
  57.  
  58. public function get_attribute_terms( $attribute ) { 
  59.  
  60. return $this->wpdb->get_results($this->wpdb->prepare(" 
  61. SELECT * FROM {$this->wpdb->term_taxonomy} x JOIN {$this->wpdb->terms} t ON x.term_id = t.term_id WHERE x.taxonomy = %s", $attribute ) ); 
  62.  
  63.  
  64. public function set_attribute_readonly_config( $id, $attribute ) { 
  65.  
  66. $is_translatable = isset( $_POST[ 'wcml-is-translatable-attr' ] ) ? 1 : 0; 
  67. $attribute_name = wc_attribute_taxonomy_name( $attribute['attribute_name'] ); 
  68. if( $is_translatable === 0 ) { 
  69. //delete all translated attributes terms if "Translatable?" option un-checked 
  70. $this->delete_translated_attribute_terms( $attribute_name ); 
  71. $this->set_variations_to_use_original_attributes( $attribute_name ); 
  72. $this->set_original_attributes_for_products( $attribute_name ); 
  73. $this->set_attribute_config_in_settings( $attribute_name, $is_translatable ); 
  74.  
  75. public function set_attribute_config_in_settings( $attribute_name, $is_translatable ) { 
  76. $this->set_attribute_config_in_wcml_settings( $attribute_name, $is_translatable ); 
  77. $this->set_attribute_config_in_wpml_settings( $attribute_name, $is_translatable ); 
  78.  
  79. $this->woocommerce_wpml->terms->update_terms_translated_status( $attribute_name ); 
  80.  
  81. public function set_attribute_config_in_wcml_settings( $attribute_name, $is_translatable ) { 
  82. $wcml_settings = $this->woocommerce_wpml->get_settings(); 
  83. $wcml_settings[ 'attributes_settings' ][ $attribute_name ] = $is_translatable; 
  84. $this->woocommerce_wpml->update_settings( $wcml_settings ); 
  85.  
  86. public function set_attribute_config_in_wpml_settings( $attribute_name, $is_translatable ) { 
  87.  
  88. $sync_settings = $this->sitepress->get_setting( 'taxonomies_sync_option', array() ); 
  89. $sync_settings[ $attribute_name ] = $is_translatable; 
  90. $this->sitepress->set_setting( 'taxonomies_sync_option', $sync_settings, true ); 
  91. $this->sitepress->verify_taxonomy_translations( $attribute_name ); 
  92.  
  93. public function delete_translated_attribute_terms( $attribute ) { 
  94. $terms = $this->get_attribute_terms( $attribute ); 
  95.  
  96. foreach( $terms as $term ) { 
  97. $term_language_details = $this->sitepress->get_element_language_details( $term->term_id, 'tax_'.$attribute ); 
  98. if( $term_language_details && $term_language_details->source_language_code ) { 
  99. wp_delete_term( $term->term_id, $attribute ); 
  100.  
  101.  
  102. public function set_variations_to_use_original_attributes( $attribute ) { 
  103. $terms = $this->get_attribute_terms( $attribute ); 
  104.  
  105. foreach( $terms as $term ) { 
  106. $term_language_details = $this->sitepress->get_element_language_details( $term->term_id, 'tax_'.$attribute ); 
  107. if( $term_language_details && is_null( $term_language_details->source_language_code ) ) { 
  108. $variations = $this->wpdb->get_results( $this->wpdb->prepare( "SELECT post_id FROM {$this->wpdb->postmeta} WHERE meta_key=%s AND meta_value = %s", 'attribute_'.$attribute, $term->slug ) ); 
  109.  
  110. foreach( $variations as $variation ) { 
  111. //update taxonomy in translation of variation 
  112. foreach( $this->sitepress->get_active_languages() as $language ) { 
  113.  
  114. $trnsl_variation_id = apply_filters( 'translate_object_id', $variation->post_id, 'product_variation', false, $language['code'] ); 
  115. if( !is_null( $trnsl_variation_id ) ) { 
  116. update_post_meta( $trnsl_variation_id, 'attribute_'.$attribute, $term->slug ); 
  117.  
  118. public function set_original_attributes_for_products( $attribute ) { 
  119.  
  120. $terms = $this->get_attribute_terms( $attribute ); 
  121. $cleared_products = array(); 
  122. foreach( $terms as $term ) { 
  123. $term_language_details = $this->sitepress->get_element_language_details( $term->term_id, 'tax_'.$attribute ); 
  124. if( $term_language_details && is_null( $term_language_details->source_language_code ) ) { 
  125. $args = array( 
  126. 'tax_query' => array( 
  127. array( 
  128. 'taxonomy' => $attribute,  
  129. 'field' => 'slug',  
  130. 'terms' => $term->slug 
  131. ); 
  132.  
  133. $products = get_posts($args); 
  134.  
  135. foreach( $products as $product ) { 
  136.  
  137. foreach( $this->sitepress->get_active_languages() as $language ) { 
  138.  
  139. $trnsl_product_id = apply_filters( 'translate_object_id', $product->ID, 'product', false, $language['code'] ); 
  140.  
  141. if ( !is_null( $trnsl_product_id ) ) { 
  142. if( !in_array( $trnsl_product_id, $trnsl_product_id ) ) { 
  143. wp_delete_object_term_relationships( $trnsl_product_id, $attribute ); 
  144. $cleared_products[] = $trnsl_product_id; 
  145. wp_set_object_terms( $trnsl_product_id, $term->slug, $attribute, true ); 
  146.  
  147.  
  148. public function is_translatable_attribute( $attr_name ) { 
  149.  
  150. if( !isset( $this->woocommerce_wpml->settings[ 'attributes_settings' ][ $attr_name ] ) ) { 
  151. $this->set_attribute_config_in_settings( $attr_name, 1 ); 
  152.  
  153. return isset( $this->woocommerce_wpml->settings[ 'attributes_settings' ][ $attr_name ] ) ? $this->woocommerce_wpml->settings[ 'attributes_settings' ][ $attr_name ] : 1; 
  154.  
  155. public function get_translatable_attributes() { 
  156. $attributes = wc_get_attribute_taxonomies(); 
  157.  
  158. $translatable_attributes = array(); 
  159. foreach( $attributes as $attribute ) { 
  160. if( $this->is_translatable_attribute( wc_attribute_taxonomy_name( $attribute->attribute_name ) ) ) { 
  161. $translatable_attributes[] = $attribute; 
  162.  
  163. return $translatable_attributes; 
  164.  
  165. public function set_translatable_attributes( $attributes ) { 
  166.  
  167. foreach( $attributes as $name => $is_translatable ) { 
  168.  
  169. $attribute_name = wc_attribute_taxonomy_name( $name ); 
  170. $this->set_attribute_config_in_settings( $attribute_name, $is_translatable ); 
  171.  
  172.  
  173. public function sync_product_attr( $original_product_id, $tr_product_id, $language = false, $data = false ) { 
  174.  
  175. //get "_product_attributes" from original product 
  176. $orig_product_attrs = $this->get_product_atributes( $original_product_id ); 
  177. $trnsl_product_attrs = $this->get_product_atributes( $tr_product_id ); 
  178.  
  179. $trnsl_labels = $this->get_attr_label_translations( $tr_product_id ); 
  180.  
  181. foreach ( $orig_product_attrs as $key => $orig_product_attr ) { 
  182. $sanitized_key = sanitize_title( $orig_product_attr[ 'name' ] ); 
  183. if( $sanitized_key != $key ) { 
  184. $orig_product_attrs_buff = $orig_product_attrs[ $key ]; 
  185. unset( $orig_product_attrs[ $key ] ); 
  186. $orig_product_attrs[ $sanitized_key ] = $orig_product_attrs_buff; 
  187. $key_to_save = $sanitized_key; 
  188. }else{ 
  189. $key_to_save = $key; 
  190. if ( $data ) { 
  191. if ( isset( $data[ md5( $key ) ] ) && !empty( $data[ md5( $key ) ] ) && !is_array( $data[ md5( $key ) ] ) ) { 
  192. //get translation values from $data 
  193. $orig_product_attrs[ $key_to_save ][ 'value' ] = $data[ md5( $key ) ]; 
  194. } else { 
  195. $orig_product_attrs[ $key_to_save ][ 'value' ] = ''; 
  196.  
  197. if ( isset( $data[ md5( $key . '_name' ) ] ) && !empty( $data[ md5( $key . '_name' ) ] ) && !is_array( $data[ md5( $key . '_name' ) ] ) ) { 
  198. //get translation values from $data 
  199. $trnsl_labels[ $language ][ $key_to_save ] = stripslashes( $data[ md5( $key . '_name' ) ] ); 
  200. } else { 
  201. $trnsl_labels[ $language ][ $key_to_save ] = ''; 
  202. }elseif( !$orig_product_attr[ 'is_taxonomy' ] ) { 
  203. if( isset( $trnsl_product_attrs[ $key ] ) ) { 
  204. $orig_product_attrs[ $key_to_save ][ 'value' ] = $trnsl_product_attrs[ $key ][ 'value' ]; 
  205. }else{ 
  206. unset ( $orig_product_attrs[ $key_to_save ] ); 
  207.  
  208. update_post_meta( $tr_product_id, 'attr_label_translations', $trnsl_labels ); 
  209. //update "_product_attributes" 
  210. update_post_meta( $tr_product_id, '_product_attributes', $orig_product_attrs ); 
  211.  
  212. public function get_product_atributes( $product_id ) { 
  213. $attributes = get_post_meta( $product_id, '_product_attributes', true ); 
  214. if( !is_array( $attributes ) ) { 
  215. $attributes = array(); 
  216. return $attributes; 
  217.  
  218. public function get_attr_label_translations( $product_id, $lang = false ) { 
  219. $trnsl_labels = get_post_meta( $product_id, 'attr_label_translations', true ); 
  220.  
  221. if( !is_array( $trnsl_labels ) ) { 
  222. $trnsl_labels = array(); 
  223.  
  224. if( isset( $trnsl_labels[ $lang ] ) ) { 
  225. return $trnsl_labels[ $lang ]; 
  226.  
  227. return $trnsl_labels; 
  228.  
  229. public function sync_default_product_attr( $orig_post_id, $transl_post_id, $lang ) { 
  230. $original_default_attributes = get_post_meta( $orig_post_id, '_default_attributes', true ); 
  231. if( !empty( $original_default_attributes ) ) { 
  232. $unserialized_default_attributes = array(); 
  233. foreach(maybe_unserialize( $original_default_attributes ) as $attribute => $default_term_slug ) { 
  234. // get the correct language 
  235. if ( substr( $attribute, 0, 3 ) == 'pa_' ) { 
  236. //attr is taxonomy 
  237. if( $this->is_translatable_attribute( $attribute ) ) { 
  238. $default_term_id = $this->woocommerce_wpml->terms->wcml_get_term_id_by_slug( $attribute, $default_term_slug ); 
  239. $tr_id = apply_filters( 'translate_object_id', $default_term_id, $attribute, false, $lang ); 
  240.  
  241. if( $tr_id ) { 
  242. $translated_term = $this->woocommerce_wpml->terms->wcml_get_term_by_id( $tr_id, $attribute ); 
  243. $unserialized_default_attributes[ $attribute ] = $translated_term->slug; 
  244. }else{ 
  245. $unserialized_default_attributes[ $attribute ] = $default_term_slug; 
  246. }else{ 
  247. //custom attr 
  248. $orig_product_attributes = get_post_meta( $orig_post_id, '_product_attributes', true ); 
  249. $unserialized_orig_product_attributes = maybe_unserialize( $orig_product_attributes ); 
  250.  
  251. if( isset( $unserialized_orig_product_attributes[ $attribute ] ) ) { 
  252. $orig_attr_values = explode( '|', $unserialized_orig_product_attributes[ $attribute ][ 'value' ] ); 
  253.  
  254. foreach( $orig_attr_values as $key => $orig_attr_value ) { 
  255. $orig_attr_value_sanitized = strtolower( sanitize_title ( $orig_attr_value ) ); 
  256.  
  257. if( $orig_attr_value_sanitized == $default_term_slug || trim( $orig_attr_value ) == trim( $default_term_slug ) ) { 
  258. $tnsl_product_attributes = get_post_meta( $transl_post_id, '_product_attributes', true ); 
  259. $unserialized_tnsl_product_attributes = maybe_unserialize( $tnsl_product_attributes ); 
  260.  
  261. if( isset( $unserialized_tnsl_product_attributes[ $attribute ] ) ) { 
  262. $trnsl_attr_values = explode( '|', $unserialized_tnsl_product_attributes[ $attribute ][ 'value' ] ); 
  263.  
  264. if( $orig_attr_value_sanitized == $default_term_slug ) { 
  265. $trnsl_attr_value = strtolower( sanitize_title( trim( $trnsl_attr_values[ $key ] ) ) ); 
  266. }else{ 
  267. $trnsl_attr_value = trim( $trnsl_attr_values[ $key ] ); 
  268. $unserialized_default_attributes[ $attribute ] = $trnsl_attr_value; 
  269.  
  270. $data = array( 'meta_value' => maybe_serialize( $unserialized_default_attributes ) ); 
  271. }else{ 
  272. $data = array( 'meta_value' => maybe_serialize( array() ) ); 
  273.  
  274. $where = array( 'post_id' => $transl_post_id, 'meta_key' => '_default_attributes' ); 
  275. $this->wpdb->update( $this->wpdb->postmeta, $data, $where ); 
  276.  
  277. /** 
  278. * get attribute translation 
  279. */ 
  280. public function get_custom_attribute_translation( $product_id, $attribute_key, $attribute, $lang_code ) { 
  281. $tr_post_id = apply_filters( 'translate_object_id', $product_id, 'product', false, $lang_code ); 
  282. $transl = array(); 
  283. if( $tr_post_id ) { 
  284. if( !$attribute[ 'is_taxonomy' ] ) { 
  285. $tr_attrs = get_post_meta($tr_post_id, '_product_attributes', true); 
  286. if( $tr_attrs ) { 
  287. foreach( $tr_attrs as $key => $tr_attr ) { 
  288. if( $attribute_key == $key ) { 
  289. $transl[ 'value' ] = $tr_attr[ 'value' ]; 
  290. $trnsl_labels = $this->get_attr_label_translations( $tr_post_id ); 
  291.  
  292. if( isset( $trnsl_labels[ $lang_code ][ $attribute_key ] ) ) { 
  293. $transl[ 'name' ] = $trnsl_labels[ $lang_code ][ $attribute_key ]; 
  294. }else{ 
  295. $transl[ 'name' ] = $tr_attr[ 'name' ]; 
  296. return $transl; 
  297. return false; 
  298. return false; 
  299.  
  300. /** 
  301. * Get custom attribute translation 
  302. * Returned translated attribute or original if missed 
  303. */ 
  304. public function get_custom_attr_translation( $product_id, $tr_product_id, $taxonomy, $attribute ) { 
  305. $orig_product_attributes = get_post_meta( $product_id, '_product_attributes', true ); 
  306. $unserialized_orig_product_attributes = maybe_unserialize( $orig_product_attributes ); 
  307.  
  308. foreach( $unserialized_orig_product_attributes as $orig_attr_key => $orig_product_attribute ) { 
  309. $orig_attr_key = urldecode( $orig_attr_key ); 
  310. if( strtolower( $taxonomy ) == $orig_attr_key ) { 
  311. $values = explode( '|', $orig_product_attribute[ 'value' ] ); 
  312.  
  313. foreach( $values as $key_id => $value ) { 
  314. if( trim( $value, " " ) == $attribute ) { 
  315. $attr_key_id = $key_id; 
  316.  
  317. $trnsl_product_attributes = get_post_meta( $tr_product_id, '_product_attributes', true ); 
  318. $unserialized_trnsl_product_attributes = maybe_unserialize( $trnsl_product_attributes ); 
  319. $taxonomy = sanitize_title( $taxonomy ); 
  320. $trnsl_attr_values = explode( '|', $unserialized_trnsl_product_attributes[ $taxonomy ][ 'value' ] ); 
  321.  
  322. if( isset( $attr_key_id ) && isset( $trnsl_attr_values[ $attr_key_id ] ) ) { 
  323. return trim( $trnsl_attr_values[ $attr_key_id ] ); 
  324.  
  325. return $attribute; 
  326.  
  327. public function filter_product_attributes_for_translation( $translated, $key ) { 
  328. $translated = $translated 
  329. ? preg_match('#^(?!field-_product_attributes-(.+)-(.+)-(?!value|name))#', $key) : 0; 
  330.  
  331. return $translated; 
  332.  
  333. public function icl_custom_tax_sync_options() { 
  334. foreach( $_POST['icl_sync_tax'] as $taxonomy => $value) { 
  335. if ( substr( $taxonomy, 0, 3 ) == 'pa_' ) { 
  336. $this->set_attribute_config_in_wcml_settings( $taxonomy , $value); 
  337.  
  338.  
  339. public function is_attributes_fully_translated() { 
  340.  
  341. $product_attributes = $this->get_translatable_attributes(); 
  342.  
  343. $fully_translated = true; 
  344.  
  345. if( $product_attributes ) { 
  346. foreach( $product_attributes as $attribute ) { 
  347. $is_fully_translated = $this->woocommerce_wpml->terms->is_fully_translated( 'pa_' . $attribute->attribute_name ); 
  348. if( !$is_fully_translated ) { 
  349. $fully_translated = false; 
  350. break; 
  351.  
  352. return $fully_translated; 
  353.  
  354. public function get_translated_variation_attribute_post_meta( $meta_value, $meta_key, $original_variation_id, $variation_id, $lang ) { 
  355.  
  356. $original_product_attr = get_post_meta( wp_get_post_parent_id( $original_variation_id ), '_product_attributes', true ); 
  357. $tr_product_attr = get_post_meta( wp_get_post_parent_id( $variation_id ), '_product_attributes', true ); 
  358.  
  359. $tax = wc_sanitize_taxonomy_name ( substr( $meta_key, 10 ) ); 
  360. if( taxonomy_exists( $tax ) ) { 
  361. $attid = $this->woocommerce_wpml->terms->wcml_get_term_id_by_slug( $tax, $meta_value ); 
  362. if( $this->is_translatable_attribute( $tax ) && $attid ) { 
  363.  
  364. $term_obj = $this->woocommerce_wpml->terms->wcml_get_term_by_id( $attid, $tax ); 
  365. $trnsl_term_id = apply_filters( 'translate_object_id', $term_obj->term_id, $tax, false, $lang ); 
  366.  
  367. if( $trnsl_term_id ) { 
  368. $trnsl_term_obj = $this->woocommerce_wpml->terms->wcml_get_term_by_id( $trnsl_term_id, $tax ); 
  369. $meta_value = $trnsl_term_obj->slug; 
  370. }else{ 
  371. if( !isset( $original_product_attr[ $tax ] ) ) { 
  372. $tax = sanitize_title( $tax ); 
  373.  
  374. if( isset( $original_product_attr[ $tax ] ) ) { 
  375. if( isset( $tr_product_attr[ $tax ] ) ) { 
  376. $values_arrs = array_map( 'trim', explode( '|', $original_product_attr[ $tax ][ 'value' ] ) ); 
  377. $values_arrs_tr = array_map( 'trim', explode( '|', $tr_product_attr[ $tax ][ 'value' ] ) ); 
  378.  
  379. foreach( $values_arrs as $key => $value ) { 
  380. $value_sanitized = sanitize_title( $value ); 
  381. if( 
  382. ( $value_sanitized == strtolower( urldecode( $meta_value ) ) || 
  383. strtolower( $value_sanitized ) == $meta_value || 
  384. $value == $meta_value ) 
  385. && isset( $values_arrs_tr[ $key ] ) ) 
  386. $meta_value = $values_arrs_tr[ $key ]; 
  387. $meta_key = 'attribute_'.$tax; 
  388.  
  389. return array( 
  390. 'meta_value' => $meta_value,  
  391. 'meta_key' => $meta_key 
  392. ); 
  393.  
  394. function filter_dropdown_variation_attribute_options_args( $args ) { 
  395.  
  396. if( isset( $args['attribute'] ) && isset( $args['product'] ) ) { 
  397. $args['attribute'] = $this->filter_attribute_name( $args['attribute'], WooCommerce_Functions_Wrapper::get_product_id( $args['product'] ) ); 
  398.  
  399. return $args; 
  400.  
  401. /** 
  402. * special case when original attribute language is German or Danish,  
  403. * needs handle special chars accordingly 
  404. * https://onthegosystems.myjetbrains.com/youtrack/issue/wcml-1785 
  405. */ 
  406. function filter_attribute_name( $attribute_name, $product_id, $return_sanitized = false ) { 
  407.  
  408. if( !is_admin() && $product_id ) { 
  409. $orig_lang = $this->woocommerce_wpml->products->get_original_product_language( $product_id ); 
  410. if ( in_array( $orig_lang, array('de', 'da' ) ) ) { 
  411. $attribute_name = $this->sitepress->locale_utils->filter_sanitize_title( remove_accents( $attribute_name ), $attribute_name ); 
  412. remove_filter( 'sanitize_title', array( $this->sitepress->locale_utils, 'filter_sanitize_title' ), 10 ); 
  413. return $attribute_name; 
  414.  
  415. if( $return_sanitized ) { 
  416. $attribute_name = sanitize_title( $attribute_name ); 
  417.  
  418. return $attribute_name; 
  419.  
  420. function filter_adding_to_cart_product_attributes_names( $attributes ) { 
  421.  
  422. if( !is_admin() && isset( $_REQUEST['add-to-cart'] ) ) { 
  423.  
  424. foreach( $attributes as $key => $attribute ) { 
  425. $attributes[ $key ]['name'] = $this->filter_attribute_name( $attributes[ $key ]['name'], $_REQUEST['add-to-cart'] ); 
  426.  
  427.  
  428. return $attributes; 
  429.