woocommerce_wpml = $woocommerce_wpml; $this->sitepress = $sitepress; $this->wpdb = $wpdb; $cache_group = 'WCML_Products'; $this->wpml_cache = is_null( $wpml_cache ) ? new WPML_WP_Cache( $cache_group ) : $wpml_cache; } public function add_hooks() { if ( is_admin() ) { add_filter( 'woocommerce_json_search_found_products', array( $this, 'woocommerce_json_search_found_products' ) ); add_filter( 'post_row_actions', array( $this, 'filter_product_actions' ), 10, 2 ); add_action( 'wp_ajax_wpml_switch_post_language', array( $this, 'switch_product_variations_language' ), 9 ); } else { add_filter( 'woocommerce_json_search_found_products', array( $this, 'filter_found_products_by_language' ) ); add_filter( 'woocommerce_related_products_args', array( $this, 'filter_related_products_args' ) ); add_filter( 'woocommerce_shortcode_products_query', array( $this, 'add_lang_to_shortcode_products_query' ) ); add_filter( 'woocommerce_product_file_download_path', array( $this, 'filter_file_download_path' ) ); } add_filter( 'woocommerce_upsell_crosssell_search_products', array( $this, 'filter_woocommerce_upsell_crosssell_posts_by_language' ) ); //update menu_order fro translations after ordering original products add_action( 'woocommerce_after_product_ordering', array( $this, 'update_all_products_translations_ordering' ) ); //filter to copy excerpt value add_filter( 'wpml_copy_from_original_custom_fields', array( $this, 'filter_excerpt_field_content_copy' ) ); add_filter( 'wpml_override_is_translator', array( $this, 'wcml_override_is_translator' ), 10, 3 ); add_filter( 'wc_product_has_unique_sku', array( $this, 'check_product_sku' ), 10, 3 ); add_filter( 'get_product_search_form', array( $this->sitepress, 'get_search_form_filter' ) ); add_filter( 'woocommerce_pre_customer_bought_product', array( $this, 'is_customer_bought_product' ), 10, 4 ); } // Check if original product public function is_original_product( $product_id ){ $cache_key = $product_id; $cache_group = 'is_original_product'; $temp_is_original = wp_cache_get($cache_key, $cache_group); if($temp_is_original) return $temp_is_original; $is_original = $this->wpdb->get_var( $this->wpdb->prepare( "SELECT source_language_code IS NULL FROM {$this->wpdb->prefix}icl_translations WHERE element_id=%d AND element_type=%s", $product_id, 'post_'.get_post_type( $product_id ) ) ); wp_cache_set( $cache_key, $is_original, $cache_group ); return $is_original; } // Get original product language public function get_original_product_language( $product_id ){ $cache_key = $product_id; $cache_group = 'original_product_language'; $temp_language = wp_cache_get( $cache_key, $cache_group ); if($temp_language) return $temp_language; $language = $this->wpdb->get_var( $this->wpdb->prepare( " SELECT t2.language_code FROM {$this->wpdb->prefix}icl_translations as t1 LEFT JOIN {$this->wpdb->prefix}icl_translations as t2 ON t1.trid = t2.trid WHERE t1.element_id=%d AND t1.element_type=%s AND t2.source_language_code IS NULL", $product_id, 'post_'.get_post_type($product_id) ) ); wp_cache_set( $cache_key, $language, $cache_group ); return $language; } public function get_original_product_id( $product_id ){ $original_product_language = $this->get_original_product_language( $product_id ); $original_product_id = apply_filters( 'translate_object_id', $product_id, get_post_type( $product_id ), true, $original_product_language ); return $original_product_id; } public function is_variable_product( $product_id ){ $cache_key = $product_id; $cache_group = 'is_variable_product'; $temp_is_variable = wp_cache_get( $cache_key, $cache_group ); if( $temp_is_variable ) return $temp_is_variable; $get_variation_term_taxonomy_ids = $this->wpdb->get_col( "SELECT tt.term_taxonomy_id FROM {$this->wpdb->terms} AS t LEFT JOIN {$this->wpdb->term_taxonomy} AS tt ON t.term_id = tt.term_id WHERE t.name = 'variable' AND tt.taxonomy = 'product_type'" ); $get_variation_term_taxonomy_ids = apply_filters( 'wcml_variation_term_taxonomy_ids',(array)$get_variation_term_taxonomy_ids ); $is_variable_product = $this->wpdb->get_var( $this->wpdb->prepare( "SELECT count(object_id) FROM {$this->wpdb->term_relationships} WHERE object_id = %d AND term_taxonomy_id IN (".join(',',$get_variation_term_taxonomy_ids).")",$product_id ) ); $is_variable_product = apply_filters( 'wcml_is_variable_product', $is_variable_product, $product_id ); wp_cache_set( $cache_key, $is_variable_product, $cache_group ); return $is_variable_product; } public function is_downloadable_product( $product ) { $cache_key = 'is_downloadable_product_'.$product->get_id(); $found = false; $is_downloadable = $this->wpml_cache->get( $cache_key, $found ); if ( ! $found ) { if ( $product->is_downloadable() ) { $is_downloadable = true; } elseif ( $this->is_variable_product( $product->get_id() ) ) { $variations = $product->get_available_variations(); if ( ! empty( $variations ) ) { foreach ( $variations as $variation ) { if ( $variation['is_downloadable'] ) { $is_downloadable = true; break; } } } } $this->wpml_cache->set( $cache_key, $is_downloadable ); } return $is_downloadable; } public function is_grouped_product($product_id){ $get_variation_term_taxonomy_id = $this->wpdb->get_var( "SELECT tt.term_taxonomy_id FROM {$this->wpdb->terms} AS t LEFT JOIN {$this->wpdb->term_taxonomy} AS tt ON t.term_id = tt.term_id WHERE t.name = 'grouped'" ); $is_grouped_product = $this->wpdb->get_var( $this->wpdb->prepare( "SELECT count(object_id) FROM {$this->wpdb->term_relationships} WHERE object_id = %d AND term_taxonomy_id = %d ",$product_id,$get_variation_term_taxonomy_id ) ); return $is_grouped_product; } public function get_translation_flags( $active_languages, $slang = false, $job_language = false ){ $available_languages = array(); foreach( $active_languages as $key => $language ){ if( $job_language && $language[ 'code' ] != $job_language ) { continue; }elseif ( !$slang || ( ( $slang != $language[ 'code' ] ) && ( current_user_can( 'wpml_operate_woocommerce_multilingual' ) || wpml_check_user_is_translator( $slang, $language[ 'code' ] ) ) && ( !isset( $_POST[ 'translation_status_lang' ] ) || ( isset( $_POST[ 'translation_status_lang' ] ) && ( $_POST[ 'translation_status_lang' ] == $language[ 'code' ] ) || $_POST[ 'translation_status_lang' ]=='' ) ) ) ){ $available_languages[ $key ][ 'name' ] = $language[ 'english_name' ]; $available_languages[ $key ][ 'flag_url' ] = $this->sitepress->get_flag_url( $language[ 'code' ] ); } } return $available_languages; } public function get_translation_statuses( $original_product_id, $product_translations, $active_languages, $slang = false, $trid = false, $job_language = false ){ foreach ( $active_languages as $language ) { if( $job_language && $language['code'] != $job_language ) { continue; }elseif( isset( $product_translations[ $language[ 'code' ] ] ) && $product_translations[ $language[ 'code' ] ]->original ) { ?> wpdb->get_var( $this->wpdb->prepare( "SELECT tj.job_id FROM {$this->wpdb->prefix}icl_translate_job AS tj LEFT JOIN {$this->wpdb->prefix}icl_translation_status AS ts ON tj.rid = ts.rid WHERE ts.translation_id=%d", $product_translations[ $language[ 'code' ] ]->translation_id ) ); }else{ $job_id = false; } if( !current_user_can( 'wpml_manage_woocommerce_multilingual' ) && isset( $product_translations[ $language[ 'code' ] ] ) ) { $tr_status = $this->wpdb->get_row( $this->wpdb->prepare( "SELECT status,translator_id FROM {$this->wpdb->prefix}icl_translation_status WHERE translation_id = %d", $product_translations[ $language[ 'code' ] ]->translation_id ) ); if( !is_null( $tr_status ) && get_current_user_id() != $tr_status->translator_id ){ if( $tr_status->status == ICL_TM_IN_PROGRESS ) { ?> status == ICL_TM_WAITING_FOR_TRANSLATOR && !$job_id ){ $tr_job_id = $this->wpdb->get_var( $this->wpdb->prepare( "SELECT j.job_id FROM {$this->wpdb->prefix}icl_translate_job j JOIN {$this->wpdb->prefix}icl_translation_status s ON j.rid = s.rid WHERE s.translation_id = %d", $product_translations[ $language[ 'code' ] ]->translation_id ) ); $translation_queue_page = admin_url( 'admin.php?page=' . WPML_TM_FOLDER . '/menu/translations-queue.php&job_id=' . $tr_job_id ); $edit_url = apply_filters( 'icl_job_edit_url', $translation_queue_page, $tr_job_id ); ?> wpdb->get_row( $this->wpdb->prepare( "SELECT status,needs_update FROM {$this->wpdb->prefix}icl_translation_status WHERE translation_id = %d", $product_translations[ $language[ 'code' ] ]->translation_id ) ); if (!$tr_status ) { ?> title=""> needs_update ){ ?> title=""> status != ICL_TM_COMPLETE && $tr_status->status != ICL_TM_DUPLICATE ){ ?> title=""> status == ICL_TM_COMPLETE ){ ?> title=""> status == ICL_TM_DUPLICATE ){ ?> title=""> title=""> post_type == 'product' && !$this->is_original_product( $post->ID ) && isset( $actions[ 'inline hide-if-no-js' ] ) ) { $new_actions = array(); foreach( $actions as $key => $action ) { if( $key == 'inline hide-if-no-js' ) { $new_actions[ 'quick_hide' ] = '' . __('Quick Edit', 'woocommerce-multilingual') . ''; } else { $new_actions[ $key ] = $action; } } return $new_actions; } return $actions; } /** * Filters upsell/crosell products in the correct language. */ public function filter_found_products_by_language( $found_products ){ $current_page_language = $this->sitepress->get_current_language(); foreach( $found_products as $product_id => $output_v ){ $post_data = $this->wpdb->get_row( $this->wpdb->prepare( "SELECT * FROM {$this->wpdb->prefix}icl_translations WHERE element_id = %d AND element_type LIKE 'post_%'", $product_id ) ); $product_language = $post_data->language_code; if( $product_language !== $current_page_language ){ unset( $found_products[ $product_id ] ); } } return $found_products; } /** * Takes off translated products from the Up-sells/Cross-sells tab. */ public function filter_woocommerce_upsell_crosssell_posts_by_language( $posts ){ foreach( $posts as $key => $post ){ $post_id = $posts[ $key ]->ID; $post_data = $this->wpdb->get_row( $this->wpdb->prepare( "SELECT * FROM {$this->wpdb->prefix}icl_translations WHERE element_id = %d ", $post_id ), ARRAY_A ); if( $post_data[ 'language_code' ] !== $this->sitepress->get_current_language() ){ unset( $posts[ $key ] ); } } return $posts; } public function woocommerce_json_search_found_products( $found_products ){ foreach( $found_products as $post => $formatted_product_name ) { $parent = wp_get_post_parent_id( $post ); if( ( isset( $_COOKIE [ '_wcml_dashboard_order_language' ] ) && ( ( !$parent && $this->sitepress->get_language_for_element( $post, 'post_product') == $_COOKIE [ '_wcml_dashboard_order_language' ] ) || ( $parent && $this->sitepress->get_language_for_element( $parent, 'post_product') == $_COOKIE [ '_wcml_dashboard_order_language' ] ) ) ) || ( ! isset( $_COOKIE [ '_wcml_dashboard_order_language' ] ) && ( ( !$parent && $this->is_original_product($post) ) || ( $parent && $this->is_original_product($parent) ) ) ) ) { $new_found_products[$post] = $formatted_product_name; } } return isset ( $new_found_products ) ? $new_found_products : $found_products ; } //update menu_order fro translations after ordering original products public function update_all_products_translations_ordering(){ if( $this->woocommerce_wpml->settings[ 'products_sync_order' ] ) { $current_language = $this->sitepress->get_current_language(); if( $current_language == $this->sitepress->get_default_language() ){ $products = $this->wpdb->get_results( $this->wpdb->prepare( "SELECT p.ID FROM {$this->wpdb->posts} AS p LEFT JOIN {$this->wpdb->prefix}icl_translations AS icl ON icl.element_id = p.id WHERE p.post_type = 'product' AND p.post_status IN ( 'publish', 'future', 'draft', 'pending', 'private' ) AND icl.element_type= 'post_product' AND icl.language_code = %s", $current_language ) ); foreach( $products as $product ){ $this->update_order_for_product_translations( $product->ID ); } } } } //update menu_order fro translations after ordering original products public function update_order_for_product_translations( $product_id ){ if( isset( $this->woocommerce_wpml->settings[ 'products_sync_order' ] ) && $this->woocommerce_wpml->settings[ 'products_sync_order' ] ){ $current_language = $this->sitepress->get_current_language(); if ( $current_language == $this->sitepress->get_default_language() ) { $menu_order = $this->wpdb->get_var( $this->wpdb->prepare("SELECT menu_order FROM {$this->wpdb->posts} WHERE ID = %d", $product_id ) ); $trid = $this->sitepress->get_element_trid($product_id, 'post_product'); $translations = $this->sitepress->get_element_translations($trid, 'post_product'); foreach( $translations as $translation ){ if( $translation->element_id != $product_id ){ $this->wpdb->update( $this->wpdb->posts, array( 'menu_order' => $menu_order ), array( 'ID' => $translation->element_id ) ); } } } } } public function filter_excerpt_field_content_copy( $elements ) { if ( $elements[ 'post_type' ] == 'product' ) { $elements[ 'excerpt' ] ['editor_type'] = 'editor'; } if ( function_exists( 'format_for_editor' ) ) { // WordPress 4.3 uses format_for_editor $elements[ 'excerpt' ][ 'value' ] = htmlspecialchars_decode( format_for_editor( $elements[ 'excerpt' ][ 'value' ], $_POST[ 'excerpt_type' ] ) ); } else { // Backwards compatible for WordPress < 4.3 if($_POST[ 'excerpt_type'] == 'rich'){ $elements[ 'excerpt' ][ 'value' ] = htmlspecialchars_decode( wp_richedit_pre( $elements[ 'excerpt' ][ 'value' ] ) ); }else{ $elements[ 'excerpt' ][ 'value' ] = htmlspecialchars_decode( wp_htmledit_pre( $elements[ 'excerpt' ][ 'value' ] ) ); } } return $elements; } // Check if user can translate product public function user_can_translate_product( $trid, $language_code ){ global $iclTranslationManagement; $current_translator = $iclTranslationManagement->get_current_translator(); $job_id = $this->wpdb->get_var( $this->wpdb->prepare(" SELECT tj.job_id FROM {$this->wpdb->prefix}icl_translate_job tj JOIN {$this->wpdb->prefix}icl_translation_status ts ON tj.rid = ts.rid JOIN {$this->wpdb->prefix}icl_translations t ON ts.translation_id = t.translation_id WHERE t.trid = %d AND t.language_code='%s' ORDER BY tj.job_id DESC LIMIT 1 ", $trid, $language_code ) ); if( $job_id && wpml_check_user_is_translator( $this->sitepress->get_source_language_by_trid( $trid ), $language_code ) ){ return true; } return false; } public function filter_related_products_args( $args ){ if( $this->woocommerce_wpml->settings[ 'enable_multi_currency' ] == WCML_MULTI_CURRENCIES_INDEPENDENT && isset( $this->woocommerce_wpml->settings[ 'display_custom_prices' ] ) && $this->woocommerce_wpml->settings[ 'display_custom_prices' ] ) { $client_currency = $this->woocommerce_wpml->multi_currency->get_client_currency(); $woocommerce_currency = get_option('woocommerce_currency'); if( $client_currency != $woocommerce_currency ){ $args['meta_query'][] = array( 'key' => '_wcml_custom_prices_status', 'value' => 1, 'compare' => '=', ); } } return $args; } /* * get meta ids for multiple values post meta key */ public function get_mid_ids_by_key( $post_id, $meta_key ) { $ids = $this->wpdb->get_col( $this->wpdb->prepare( "SELECT meta_id FROM {$this->wpdb->postmeta} WHERE post_id = %d AND meta_key = %s", $post_id, $meta_key ) ); if( $ids ) return $ids; return false; } // count "in progress" and "waiting on translation" as untranslated too public function get_untranslated_products_count( $language ){ $count = 0; $products = $this->wpdb->get_results( " SELECT p.ID, t.trid, t.language_code FROM {$this->wpdb->posts} AS p LEFT JOIN {$this->wpdb->prefix}icl_translations AS t ON t.element_id = p.id WHERE p.post_type = 'product' AND t.element_type = 'post_product' AND t.source_language_code IS NULL " ); foreach( $products as $product ){ if( $product->language_code == $language ) continue; $translation_status = apply_filters( 'wpml_translation_status', null, $product->trid, $language ); if( in_array( $translation_status, array( ICL_TM_NOT_TRANSLATED, ICL_TM_WAITING_FOR_TRANSLATOR, ICL_TM_IN_PROGRESS ) ) ){ $count++; } } return $count; } public function is_hide_resign_button(){ global $iclTranslationManagement; $hide_resign = false; if( isset( $_GET[ 'source_language_code' ] ) && isset( $_GET[ 'language_code' ] ) ){ $from_lang = $_GET[ 'source_language_code' ]; $to_lang = $_GET[ 'language_code' ]; }elseif( isset( $_GET[ 'job_id' ] ) ){ $job = $iclTranslationManagement->get_translation_job( $_GET[ 'job_id' ] ); $from_lang = $job->source_language_code; $to_lang = $job->language_code; } if( isset( $from_lang ) ){ $translators = $iclTranslationManagement->get_blog_translators( array( 'from' => $from_lang, 'to' => $to_lang ) ); if( empty( $translators ) || ( sizeof( $translators ) == 1 && $translators[0]->ID == get_current_user_id() ) ){ $hide_resign = true; } } return $hide_resign; } public function switch_product_variations_language(){ $lang_to = false; $post_id = false; if ( isset( $_POST[ 'wpml_to' ] ) ) { $lang_to = $_POST[ 'wpml_to' ]; } if ( isset( $_POST[ 'wpml_post_id' ] ) ) { $post_id = $_POST[ 'wpml_post_id' ]; } if ( $post_id && $lang_to && get_post_type( $post_id ) == 'product' ) { $product_variations = $this->woocommerce_wpml->sync_variations_data->get_product_variations( $post_id ); foreach( $product_variations as $product_variation ){ $trid = $this->sitepress->get_element_trid( $product_variation->ID, 'post_product_variation' ); $current_prod_variation_id = apply_filters( 'translate_object_id', $product_variation->ID, 'product_variation', false, $lang_to ); if( is_null( $current_prod_variation_id ) ){ $this->sitepress->set_element_language_details( $product_variation->ID, 'post_product_variation', $trid, $lang_to ); foreach( get_post_custom( $product_variation->ID ) as $meta_key => $meta ) { foreach ( $meta as $meta_value ) { if ( substr( $meta_key, 0, 10 ) == 'attribute_' ) { $trn_post_meta = $this->woocommerce_wpml->attributes->get_translated_variation_attribute_post_meta( $meta_value, $meta_key, $product_variation->ID, $product_variation->ID, $lang_to ); update_post_meta( $product_variation->ID, $trn_post_meta['meta_key'], $trn_post_meta['meta_value']); } } } } } } } function check_product_sku( $sku_found, $product_id, $sku ) { if ( $sku_found ) { $product_trid = $this->sitepress->get_element_trid( $product_id, 'post_' . get_post_type( $product_id ) ); $products = $this->wpdb->get_results( $this->wpdb->prepare( " SELECT p.ID FROM {$this->wpdb->posts} as p LEFT JOIN {$this->wpdb->postmeta} as pm ON ( p.ID = pm.post_id ) WHERE p.post_type IN ( 'product', 'product_variation' ) AND p.post_status = 'publish' AND pm.meta_key = '_sku' AND pm.meta_value = '%s' ", wp_slash( $sku ) ) ); $sku_found = false; foreach ( (array) $products as $product ) { $trid = $this->sitepress->get_element_trid( $product->ID, 'post_' . get_post_type( $product_id ) ); if ( $product_trid !== $trid ) { $sku_found = true; break; } } } return $sku_found; } public function add_lang_to_shortcode_products_query( $query_args ){ $query_args[ 'lang' ] = $this->sitepress->get_current_language(); return $query_args; } /** * Get file download path in correct domain * * @param string $file_path file path URL * @return string */ public function filter_file_download_path( $file_path ) { $is_per_domain = $this->sitepress->get_wp_api()->constant( 'WPML_LANGUAGE_NEGOTIATION_TYPE_DOMAIN' ) === (int) $this->sitepress->get_setting( 'language_negotiation_type' ); if ( $is_per_domain ) { $wpml_url_helper = new WPML_URL_Converter_Url_Helper(); if( strpos( trim( $file_path ), $wpml_url_helper->get_abs_home() ) === 0 ){ $file_path = $this->sitepress->convert_url( $file_path ); } } return $file_path; } /** * * @return bool */ public function is_product_display_as_translated_post_type() { return apply_filters( 'wpml_is_display_as_translated_post_type', false, 'product' ); } public function is_customer_bought_product( $value, $customer_email, $user_id, $product_id ){ if ( !$this->is_original_product( $product_id ) ){ remove_filter( 'woocommerce_pre_customer_bought_product', array( $this, 'is_customer_bought_product' ), 10, 4 ); $value = wc_customer_bought_product( $customer_email, $user_id, $this->get_original_product_id( $product_id ) ); add_filter( 'woocommerce_pre_customer_bought_product', array( $this, 'is_customer_bought_product' ), 10, 4 ); } return $value; } }