509318396
­­­­­­­­­­­­­­­­­­
<!DOCTYPE html>
<html>
<?php

use WCML\Permalinks\Strings;
use WCML\Utilities\WCTaxonomies;

class WCML_Url_Translation {
	const WC_STRING_CONTEXT = 'WooCommerce Endpoints';
	

	private $woocommerce_wpml;
	private $sitepress;
	private $wpdb;
	private $attributeBaseReplacements = [];

	public $default_product_base;
	public $default_product_category_base;
	public $default_product_category_gettext_base;
	public $default_product_tag_base;
	public $default_product_tag_gettext_base;
	public $wc_permalinks;

	public function __construct( woocommerce_wpml $woocommerce_wpml, \WPML\Core\ISitePress $sitepress, wpdb $wpdb ) {
		$this->woocommerce_wpml = $woocommerce_wpml;
		$this->sitepress        = $sitepress;
		$this->wpdb             = $wpdb;

		$this->default_product_base                  = Strings::DEFAULT_PRODUCT_BASE;
		$this->default_product_category_base         = Strings::DEFAULT_PRODUCT_CATEGORY_BASE;
		$this->default_product_tag_base              = Strings::DEFAULT_PRODUCT_TAG_BASE;
		$this->default_product_category_gettext_base = _x( Strings::DEFAULT_PRODUCT_CATEGORY_BASE, 'slug', 'woocommerce' );
		$this->default_product_tag_gettext_base      = _x( Strings::DEFAULT_PRODUCT_TAG_BASE, 'slug', 'woocommerce' );
	}

	public function set_up() {

		$this->wc_permalinks = get_option( 'woocommerce_permalinks' );

		if ( ! is_admin() ) {
			add_filter(
				'option_woocommerce_permalinks',
				[
					$this,
					'use_untranslated_default_url_bases',
				],
				1,
				1
			);
			add_action(
				'init',
				[
					$this,
					'fix_post_object_rewrite_slug',
				],
				6
			);
		}

		add_filter(
			'pre_update_option_rewrite_rules',
			[
				$this,
				'force_bases_in_strings_languages',
			],
			1,
			1
		);
		add_filter( 'option_rewrite_rules', [ $this, 'translate_bases_in_rewrite_rules' ], 0, 1 );
		foreach ( [ 'wpml_st_add_string_translation', 'wpml_st_string_updated', 'woocommerce_attribute_added', 'woocommerce_attribute_updated', 'woocommerce_attribute_deleted', 'switch_blog' ] as $action ) {
			add_action( $action, [ $this, 'resetAttributeBaseReplacements' ] );
		}
		add_filter( 'term_link', [ $this, 'translate_taxonomy_base' ], 0, 3 );
		add_filter( 'woocommerce_taxonomy_archive_description_raw', [ $this, 'process_taxonomy_description_links' ], 10, 2 );

		\WCML\Request\Ajax::register( 'wcml_update_base_translation', [ 'authorize' => [ 'WCML_Capabilities', 'canManageWcml' ], 'description' => 'WCML manager (shop manager or administrator role, WCML_Capabilities::canManageWcml)', 'nonce' => [ 'wcml_update_base_translation', 'wcml_nonce' ] ], [ $this, 'wcml_update_base_translation' ] );
		add_filter( 'redirect_canonical', [ $this, 'check_wc_tax_url_on_redirect' ], 10, 2 );
		add_filter( 'query_vars', [ $this, 'translate_query_var_for_product' ] );
		add_filter( 'wp_redirect', [ $this, 'encode_shop_slug' ] );
		add_action( 'switch_blog', [ $this, 'maybe_remove_query_vars_filter' ] );

		add_filter( 'post_type_link', [ $this, 'translate_product_post_type_link' ], 10, 2 );

		if ( empty( $this->woocommerce_wpml->settings['url_translation_set_up'] ) ) {

			$this->clean_up_product_and_taxonomy_bases();

			$this->translate_product_base();

			$this->register_product_and_taxonomy_bases();

			$this->woocommerce_wpml->settings['url_translation_set_up'] = 1;
			$this->woocommerce_wpml->update_settings();
		}

		add_action( 'init', [ $this, 'add_hooks_after_init' ], PHP_INT_MAX );
	}

	public function add_hooks_after_init() {
		if ( ! is_admin() ) {
			if ( $this->isProductDisplayAsTranslatedDocument() ) {
				add_filter( 'wpml_st_post_type_link_filter_language_details', [ $this, 'translate_product_slug_when_product_is_display_as_translated_document' ] );
			}
		}

		if ( $this->woocommerce_wpml->products->is_product_display_as_translated_post_type() ) {
			if ( false !== strpos( $this->get_woocommerce_product_base(), '%product_cat%' ) ) {
				add_filter( 'wc_product_post_type_link_product_cat', [ $this, 'translate_product_post_type_link_product_cat_when_display_as_translated' ], 10, 3 );
			}
		}

		add_filter( 'wpml_absolute_links_permalink_query_vars', [ $this, 'adjustQueryVarsOfShopAbsoluteLink' ], 10, 3 );
	}

	public function adjustQueryVarsOfShopAbsoluteLink( $permalink_query_vars, $query, $language ) {
		if ( 'post_type=product' === $query ) {
			$shopId           = wc_get_page_id( 'shop' );
			$translatedShopId = $shopId > 0 ? apply_filters( 'wpml_object_id', $shopId, 'page', true, $language ) : 0;
			$pagename         = $translatedShopId > 0 ? get_page_uri( $translatedShopId ) : '';

			if ( $pagename ) {
				return [
					'pagename' => $pagename,
					'page'     => '',
				];
			}
		}

		return $permalink_query_vars;
	}

	public function translate_product_slug_when_product_is_display_as_translated_document( $elementLanguageDetails ) {
		if ( $elementLanguageDetails->source_language_code ) {
			return $elementLanguageDetails;
		}

		if ( 'product' !== get_post_type( $elementLanguageDetails->element_id ) ) {
			return $elementLanguageDetails;
		}

		$elementLanguageDetails->source_language_code = $elementLanguageDetails->language_code;
		$elementLanguageDetails->language_code        = $this->sitepress->get_current_language();

		return $elementLanguageDetails;
	}

	private function isProductDisplayAsTranslatedDocument(): bool {
		return in_array( 'product', \WPML\API\PostTypes::getDisplayAsTranslated(), true );
	}

	public function flushWcSettings() {
		$this->wc_permalinks = get_option( 'woocommerce_permalinks' );
	}

	public function clean_up_product_and_taxonomy_bases() {

		$base = $this->get_woocommerce_product_base();

		$this->wpdb->query( 
			$this->wpdb->prepare(
				"DELETE FROM {$this->wpdb->prefix}icl_strings WHERE context = %s AND value != %s AND name LIKE 'URL slug:%' ",
				Strings::TRANSLATION_DOMAIN,
				trim( $base, '/' )
			)
		);

		$this->wpdb->update(
			$this->wpdb->prefix . 'icl_strings',
			[
				'context' => Strings::TRANSLATION_DOMAIN,
				'name'    => 'URL slug: product',
			],
			[
				'context' => Strings::TRANSLATION_DOMAIN,
				'name'    => sprintf( 'Url slug: %s', trim( $base, '/' ) ),
			]
		);

		$woocommerce_permalinks = maybe_unserialize( get_option( 'woocommerce_permalinks' ) );

		foreach ( (array) $woocommerce_permalinks as $base_key => $base ) {

			$base_key = trim( $base_key, '/' );

			$taxonomy = false;

			switch ( $base_key ) {
				case 'category_base':
					$taxonomy = 'product_cat';
					break;
				case 'tag_base':
					$taxonomy = 'product_tag';
					break;
				case 'attribute_base':
					$taxonomy = 'attribute';
					break;
			}

			if ( $taxonomy ) {
				$this->wpdb->query( "DELETE FROM {$this->wpdb->prefix}icl_strings WHERE context LIKE '" . sprintf( 'URL %s slugs - ', $taxonomy ) . "%'" );
			}
		}

	}

	public function fix_post_object_rewrite_slug() {
		global $wp_post_types, $wp_rewrite;

		if ( empty( $this->wc_permalinks['product_base'] ) ) {
			$wp_post_types['product']->rewrite['slug'] = 'product';
			if ( empty( $wp_rewrite->extra_permastructs['product']['struct'] ) ) {
				$wp_rewrite->extra_permastructs['product']['struct'] = '/product/%product%';
			}
		}
	}

	public function url_strings_context() {
		return Strings::TRANSLATION_DOMAIN;
	}

	public function url_string_name( $type, $value = '' ) {
		return Strings::getStringName( $type, $value );
	}

	public function translate_product_base() {
		if ( ! defined( 'WOOCOMMERCE_VERSION' ) || ( ! isset( $GLOBALS['ICL_Pro_Translation'] ) ) ) {
			return;
		}

		$slug = $this->get_woocommerce_product_base();
		do_action( 'wpml_activate_slug_translation', 'product', $slug );
	}

	public function get_woocommerce_product_base() {

		if ( isset( $this->wc_permalinks['product_base'] ) && ! empty( $this->wc_permalinks['product_base'] ) ) {
			return trim( $this->wc_permalinks['product_base'], '/' );
		} elseif ( get_option( 'woocommerce_product_slug' ) != false ) {
			return trim( get_option( 'woocommerce_product_slug' ), '/' );
		} else {
			return $this->default_product_base;
		}

	}

	public function register_product_and_taxonomy_bases( $wcPermalinks = false, $deprecated = false ) {

		if ( empty( $wcPermalinks ) ) {
			$permalink_options = $this->wc_permalinks;
		} else {
			$permalink_options = $wcPermalinks;
		}

		$product_base = ! empty( $permalink_options['product_base'] ) ? trim( $permalink_options['product_base'], '/' ) : $this->default_product_base;
		$name         = Strings::getStringName( 'product' );

		$string_language = $this->woocommerce_wpml->strings->get_string_language( $product_base, Strings::TRANSLATION_DOMAIN, $name );
		if ( is_null( $string_language ) ) {
			$string_language = '';
		}
		do_action( 'wpml_register_single_string', Strings::TRANSLATION_DOMAIN, $name, $product_base, false, $string_language );

		if ( isset( $_POST['product_base_language'] ) ) {
			$this->woocommerce_wpml->strings->set_string_language( $product_base, Strings::TRANSLATION_DOMAIN, $name, $_POST['product_base_language'] );
		}

		if ( $product_base == $this->default_product_base ) {
			$this->add_default_slug_translations( $product_base, $name );
		}

		$category_base = ! empty( $permalink_options['category_base'] ) ? $permalink_options['category_base'] : $this->default_product_category_base;
		$name          = Strings::getStringName( 'product_cat' );

		$string_language = $this->woocommerce_wpml->strings->get_string_language( $category_base, Strings::TRANSLATION_DOMAIN, $name );
		if ( is_null( $string_language ) ) {
			$string_language = '';
		}
		do_action( 'wpml_register_single_string', Strings::TRANSLATION_DOMAIN, $name, $category_base, false, $string_language );

		if ( isset( $_POST['category_base_language'] ) ) {
			$this->woocommerce_wpml->strings->set_string_language( $category_base, Strings::TRANSLATION_DOMAIN, $name, $_POST['category_base_language'] );
		}

		if ( $category_base == $this->default_product_category_base ) {
			$this->add_default_slug_translations( $category_base, $name );
		}

		$tag_base = ! empty( $permalink_options['tag_base'] ) ? $permalink_options['tag_base'] : $this->default_product_tag_base;
		$name     = Strings::getStringName( 'product_tag' );

		$string_language = $this->woocommerce_wpml->strings->get_string_language( $tag_base, Strings::TRANSLATION_DOMAIN, $name );
		if ( is_null( $string_language ) ) {
			$string_language = '';
		}
		do_action( 'wpml_register_single_string', Strings::TRANSLATION_DOMAIN, $name, $tag_base, false, $string_language );

		if ( isset( $_POST['tag_base_language'] ) ) {
			$this->woocommerce_wpml->strings->set_string_language( $tag_base, Strings::TRANSLATION_DOMAIN, $name, $_POST['tag_base_language'] );
		}

		if ( $tag_base == $this->default_product_tag_base ) {
			$this->add_default_slug_translations( $tag_base, $name );
		}

		if ( isset( $permalink_options['attribute_base'] ) && $permalink_options['attribute_base'] ) {
			$attr_base = trim( $permalink_options['attribute_base'], '/' );
			$attr_string_name = Strings::getStringName( 'attribute' );

			$string_language = $this->woocommerce_wpml->strings->get_string_language( $attr_base, Strings::TRANSLATION_DOMAIN, $attr_string_name );
			if ( is_null( $string_language ) ) {
				$string_language = '';
			}
			do_action( 'wpml_register_single_string', Strings::TRANSLATION_DOMAIN, $attr_string_name, $attr_base, false, $string_language );

			if ( isset( $_POST['attribute_base_language'] ) ) {
				$this->woocommerce_wpml->strings->set_string_language( $attr_base, Strings::TRANSLATION_DOMAIN, $attr_string_name, $_POST['attribute_base_language'] );
			}
		}

		return $wcPermalinks;
	}

	public function use_untranslated_default_url_bases( $permalinks ) {

		if ( preg_match( '#^/?index\.php/#', get_option( 'permalink_structure' ) ) ) {
			return $permalinks;
		}

		if ( empty( $permalinks['product_base'] ) ) {
			$permalinks['product_base'] = $this->default_product_base;
		}
		if ( empty( $permalinks['category_base'] ) ) {
			$permalinks['category_base'] = $this->default_product_category_base;
		}
		if ( empty( $permalinks['tag_base'] ) ) {
			$permalinks['tag_base'] = $this->default_product_tag_base;
		}

		return $permalinks;
	}

	public function add_default_slug_translations( $slug, $name ) {

		$string_id       = icl_get_string_id( $slug, Strings::TRANSLATION_DOMAIN, $name );
		$string_language = $this->woocommerce_wpml->strings->get_string_language( $slug, Strings::TRANSLATION_DOMAIN, $name );

		$string_object               = new WPML_ST_String( $string_id, $this->wpdb );
		$string_translation_statuses = $string_object->get_translation_statuses();

		foreach ( $string_translation_statuses as $s ) {
			$string_translations[ $s->language ] = $s->status;
		}

		$languages = $this->sitepress->get_active_languages();

		foreach ( $languages as $language => $language_info ) {

			if ( $language != $string_language ) {

				if ( ! isset( $string_translations[ $language ] ) ) {

					$slug_translation = $this->woocommerce_wpml->strings->get_translation_from_woocommerce_mo_file( $slug, $language, false );

					if ( $slug_translation ) {
						icl_add_string_translation( $string_id, $language, $slug_translation, ICL_STRING_TRANSLATION_COMPLETE );
					}
				}
			}
		}

	}

	public function force_bases_in_strings_languages( $value ) {

		if ( $value && ! \WCML\Utilities\LanguageCode::isEnglish( $this->sitepress->get_current_language() ) ) {

			remove_filter(
				'gettext_with_context',
				[
					$this->woocommerce_wpml->strings,
					'category_base_in_strings_language',
				],
				99
			);
			$taxonomies = [
				'product_cat' => [
					'base'            => 'category_base',
					'base_translated' => apply_filters(
						'wpml_translate_single_string',
						'product-category',
						Strings::TRANSLATION_DOMAIN,
						Strings::getStringName( 'product_cat' )
					),
					'default'         => $this->default_product_category_base,
				],
				'product_tag' => [
					'base'            => 'tag_base',
					'base_translated' => apply_filters(
						'wpml_translate_single_string',
						'product-tag',
						Strings::TRANSLATION_DOMAIN,
						Strings::getStringName( 'product_tag' )
					),
					'default'         => $this->default_product_tag_base,
				],
			];
			add_filter(
				'gettext_with_context',
				[
					$this->woocommerce_wpml->strings,
					'category_base_in_strings_language',
				],
				99,
				3
			);
			foreach ( $taxonomies as $taxonomy_details ) {

				if ( empty( $this->wc_permalinks[ $taxonomy_details['base'] ] ) && $value ) {

					$new_value = [];
					foreach ( $value as $k => $v ) {
						$k               = preg_replace( '#' . preg_quote( $taxonomy_details['base_translated'], '#' ) . '/#', $taxonomy_details['default'] . '/', $k );
						$new_value[ $k ] = $v;
					}
					$value = $new_value;
					unset( $new_value );

				}
			}
		}

		return $value;

	}

	public function translate_bases_in_rewrite_rules( $value ) {

		if ( ! empty( $value ) ) {
			$value = $this->translate_wc_default_taxonomies_bases_in_rewrite_rules( $value );
			$value = $this->translate_attributes_bases_in_rewrite_rules( $value );
			$value = $this->translate_shop_page_base_in_rewrite_rules( $value );
		}

		return $value;
	}

	public function translate_wc_default_taxonomies_bases_in_rewrite_rules( $value ) {
		$taxonomies = [ WCTaxonomies::TAXONOMY_PRODUCT_CATEGORY, WCTaxonomies::TAXONOMY_PRODUCT_TAG ];

		foreach ( $taxonomies as $taxonomy ) {
			$slug_details = $this->get_translated_tax_slug( $taxonomy );

			$string_language = $this->woocommerce_wpml->strings->get_string_language( $slug_details['slug'], Strings::TRANSLATION_DOMAIN, Strings::getStringName( $taxonomy ) );
			if ( $this->sitepress->get_current_language() == $string_language ) {
				continue;
			}

			if ( $slug_details ) {

				$slug_match             = preg_quote( ltrim( $slug_details['slug'], '/' ), '#' );
				$slug_translation_match = addcslashes( ltrim( $slug_details['translated_slug'], '/' ), '\\$' );

				$buff_value = [];

				foreach ( (array) $value as $k => $v ) {

					if ( $slug_details['slug'] != $slug_details['translated_slug'] && preg_match( '#(^|^/)' . $slug_match . '/#', $k ) ) {
						$k = preg_replace( '#(^|^/)' . $slug_match . '/#', '$1' . $slug_translation_match . '/', $k );
					}

					$buff_value[ $k ] = $v;
				}
				$value = $buff_value;
				unset( $buff_value );
			}
		}

		return $value;
	}

	public function translate_attributes_bases_in_rewrite_rules( $value ) {
		foreach ( $this->getAttributeBaseReplacements() as list( $pattern, $replacement_pattern, $replacement ) ) {
			$value = $this->replace_bases_in_rewrite_rules( $value, $pattern, $replacement_pattern, $replacement );
		}

		return $value;
	}

	private function getAttributeBaseReplacements(): array {
		$language = (string) $this->sitepress->get_current_language();

		if ( isset( $this->attributeBaseReplacements[ $language ] ) ) {
			return $this->attributeBaseReplacements[ $language ];
		}

		$replacements = [];

		foreach ( wc_get_attribute_taxonomies() as $attribute ) {
			$taxonomy_obj = get_taxonomy( WCTaxonomies::TAXONOMY_PREFIX_ATTRIBUTE . $attribute->attribute_name );

			if ( isset( $taxonomy_obj->rewrite['slug'] ) ) {
				$exp            = explode( '/', trim( $taxonomy_obj->rewrite['slug'], '/' ) );
				$slug           = join( '/', array_slice( $exp, 0, count( $exp ) - 1 ) );
				$attribute_slug = preg_replace( '#^' . preg_quote( $slug, '#' ) . '/#', '', $taxonomy_obj->rewrite['slug'] );

				$slug_translation = $slug ? apply_filters( 'wpml_translate_single_string', $slug, Strings::TRANSLATION_DOMAIN, Strings::getStringName( 'attribute' ) ) : '';

				$attribute_slug_translation = apply_filters( 'wpml_translate_single_string', $attribute_slug, Strings::TRANSLATION_DOMAIN, Strings::getStringName( 'attribute_slug', $attribute_slug ) );

				if ( $slug && $slug_translation && $slug !== $slug_translation ) {

					$slug_match             = preg_quote( ltrim( $slug, '/' ), '#' );
					$slug_translation_match = addcslashes( ltrim( $slug_translation, '/' ), '\\$' );

					$pattern             = '#^' . $slug_match . '/(.*)#';
					$replacement_pattern = '#^' . $slug_match . '/(' . preg_quote( $attribute_slug, '#' ) . ')/(.*)#';
					$replacement         = $slug_translation_match . '/' . addcslashes( $attribute_slug_translation, '\\$' ) . '/$2';

					$replacements[] = [ $pattern, $replacement_pattern, $replacement ];

				} elseif ( $attribute_slug_translation && $attribute_slug !== $attribute_slug_translation ) {

					$slug_match  = preg_quote( ltrim( $attribute_slug, '/' ), '#' );
					$pattern     = '#(^|\/)' . $slug_match . '/(.*)#';
					$replacement = '$1' . addcslashes( $attribute_slug_translation, '\\$' ) . '/$2';

					$replacements[] = [ $pattern, $pattern, $replacement ];

				}
			}
		}

		if ( did_action( 'wp_loaded' ) ) {
			$this->attributeBaseReplacements[ $language ] = $replacements;
		}

		return $replacements;
	}

	public function resetAttributeBaseReplacements(): void {
		$this->attributeBaseReplacements = [];
	}

	public function translate_shop_page_base_in_rewrite_rules( $value ) {
		$current_shop_id = wc_get_page_id( 'shop' );
		$default_shop_id = apply_filters( 'wpml_object_id', $current_shop_id, 'page', true, $this->sitepress->get_default_language() );

		if ( is_null( get_post( $current_shop_id ) ) || is_null( get_post( $default_shop_id ) ) ) {
			return $value;
		}

		$current_slug = urldecode( get_page_uri( $current_shop_id ) );
		$default_slug = urldecode( get_page_uri( $default_shop_id ) );

		if ( $current_slug != $default_slug ) {
			$default_slug_match = preg_quote( $default_slug, '#' );

			$buff_value = [];
			foreach ( (array) $value as $k => $v ) {

				if ( preg_match( '#^' . $default_slug_match . '/\?\$$#', $k ) ||
					 preg_match( '#^' . $default_slug_match . '/\(?feed#', $k ) ||
					 preg_match( '#^' . $default_slug_match . '/page#', $k )
				) {

					$k = preg_replace( '#^' . $default_slug_match . '/#', addcslashes( $current_slug, '\\$' ) . '/', $k );
				}

				$buff_value[ $k ] = $v;
			}

			$value = $buff_value;
			unset( $buff_value );
		}

		return $value;
	}

	public function replace_bases_in_rewrite_rules( $value, $pattern, $replacement_pattern, $replacement ) {

		$buff_value = [];
		foreach ( (array) $value as $k => $v ) {
			if ( preg_match( $pattern, $k ) ) {
				$k = preg_replace( $replacement_pattern, $replacement, $k );
			}
			$buff_value[ $k ] = $v;
		}

		$value = $buff_value;
		unset( $buff_value );

		return $value;
	}

	public function translate_taxonomy_base( $termlink, $term, $taxonomy ) {
		global $wp_rewrite, $wpml_term_translations;
		static $no_recursion_flag;

		$wc_taxonomies = wc_get_attribute_taxonomies();
		foreach ( $wc_taxonomies as $v ) {
			$wc_taxonomies_wc_format[] = WCTaxonomies::TAXONOMY_PREFIX_ATTRIBUTE . $v->attribute_name;
		}

		if ( ( WCTaxonomies::isProductAttribute( $taxonomy ) || WCTaxonomies::isProductTag( $taxonomy ) || ( ! empty( $wc_taxonomies_wc_format ) && in_array( $taxonomy, $wc_taxonomies_wc_format ) ) ) && ! $no_recursion_flag ) {

			$cache_key = 'termlink#' . $taxonomy . '#' . $term->term_id;
			if ( $link = wp_cache_get( $cache_key, 'terms' ) ) {
				$termlink = $link;
			} else {

				$no_recursion_flag = false;

				if ( ! is_null( $wpml_term_translations ) ) {
					$term_language = $term->term_id ? $wpml_term_translations->get_element_lang_code( $term->term_taxonomy_id ) : false;
				} else {
					$term_language = $term->term_id ? $this->sitepress->get_language_for_element( $term->term_taxonomy_id, 'tax_' . $taxonomy ) : false;
				}

				if ( $term_language ) {

					$slug_details = $this->get_translated_tax_slug( $taxonomy, $term_language );

					$base            = $slug_details['slug'];
					$base_translated = $slug_details['translated_slug'];

					if ( isset( $wp_rewrite->extra_permastructs[ $taxonomy ] ) ) {

						$buff = $wp_rewrite->extra_permastructs[ $taxonomy ]['struct'];

						if ( $base_translated !== $base ) {
							$wp_rewrite->extra_permastructs[ $taxonomy ]['struct'] = preg_replace( '#^' . preg_quote( $base, '#' ) . '/(.*)#', addcslashes( $base_translated, '\\$' ) . '/$1', $wp_rewrite->extra_permastructs[ $taxonomy ]['struct'] );
						}

						$attribute_slug             = preg_replace( '#^' . preg_quote( $base, '#' ) . '/([^/]+)/.+$#', '$1', $wp_rewrite->extra_permastructs[ $taxonomy ]['struct'] );
						$attribute_slug_default     = preg_replace( '#^pa_#', '', $taxonomy );
						$attribute_slug_translation = apply_filters(
							'wpml_translate_single_string',
							$attribute_slug,
							Strings::TRANSLATION_DOMAIN,
							Strings::getStringName( 'attribute_slug', $attribute_slug_default ),
							$term_language
						);

						if ( $attribute_slug_translation != $attribute_slug ) {

							if ( $base ) {
								$wp_rewrite->extra_permastructs[ $taxonomy ]['struct'] = preg_replace(
									'#^' . preg_quote( $base_translated, '#' ) . '/([^/]+)/(.+)$#',
									addcslashes( $base_translated, '\\$' ) . '/' . addcslashes( $attribute_slug_translation, '\\$' ) . '/$2',
									$wp_rewrite->extra_permastructs[ $taxonomy ]['struct']
								);
							} else {
								$wp_rewrite->extra_permastructs[ $taxonomy ]['struct'] = preg_replace(
									'#' . preg_quote( $attribute_slug_default, '#' ) . '/(.+)$#',
									addcslashes( $attribute_slug_translation, '\\$' ) . '/$1',
									$wp_rewrite->extra_permastructs[ $taxonomy ]['struct']
								);
							}
						}

						$no_recursion_flag = true;
						$termlink          = get_term_link( $term, $taxonomy );

						$wp_rewrite->extra_permastructs[ $taxonomy ]['struct'] = $buff;

					}
				}

				$no_recursion_flag = false;

				wp_cache_add( $cache_key, $termlink, 'terms', 0 );
			}
		}

		return $termlink;
	}

	public function process_taxonomy_description_links( $term_description, $term ) {
		if ( ! is_string( $term_description ) ) {
			return $term_description;
		}

		return (string) apply_filters( 'wpml_translate_link_targets', $term_description );
	}

	public function get_translated_tax_slug( $taxonomy, $language = false ) {

		switch ( $taxonomy ) {
			case 'product_tag':
				if ( ! empty( $this->wc_permalinks['tag_base'] ) ) {
					$slug = trim( $this->wc_permalinks['tag_base'], '/' );
				} else {
					$slug = 'product-tag';
				}

				$string_language = $this->woocommerce_wpml->strings->get_string_language( $slug, Strings::TRANSLATION_DOMAIN, Strings::getStringName( $taxonomy ) );

				break;

			case 'product_cat':
				if ( ! empty( $this->wc_permalinks['category_base'] ) ) {
					$slug = trim( $this->wc_permalinks['category_base'], '/' );
				} else {
					$slug = 'product-category';
				}

				$string_language = $this->woocommerce_wpml->strings->get_string_language( $slug, Strings::TRANSLATION_DOMAIN, Strings::getStringName( $taxonomy ) );

				break;

			default:
				$slug = trim( $this->wc_permalinks['attribute_base'], '/' );

				$string_language = $this->woocommerce_wpml->strings->get_string_language( $slug, Strings::TRANSLATION_DOMAIN, Strings::getStringName( 'attribute' ) );

				$taxonomy = 'attribute';

				break;
		}

		if ( ! $language ) {
			$language = $this->sitepress->get_current_language();
		}

		if ( $slug && $language !== 'all' && $language !== $string_language ) {

			return [
				'slug'            => $slug,
				'translated_slug' => $this->getCompletedBaseTranslation( $slug, $taxonomy, $language ),
			];
		}

		return [
			'slug'            => $slug,
			'translated_slug' => $slug,
		];

	}

	private function getCompletedBaseTranslation( $slug, $taxonomy, $language ) {
		if ( ! class_exists( WPML_Slug_Translation_Factory::class ) ) {
			return $slug;
		}

		return (string) apply_filters(
			'wpml_get_translated_slug',
			$slug,
			$taxonomy,
			$language,
			WPML_Slug_Translation_Factory::TAX
		);
	}

	public function get_base_translation( $base, $language ) {
		$original_base = $base;

		if ( strpos( $base, 'attribute_slug-' ) === 0 ) {
			$base = 'attribute_slug';
		}

		switch ( $base ) {
			case 'product':
				$slug           = $this->get_woocommerce_product_base();
				/* translators: Name of the URL part that precedes every product address, on the plugin's store URLs screen. */
				$return['name'] = __( 'Product Base', 'woocommerce-multilingual' );
				break;

			case 'product_tag':
				$slug           = ! empty( $this->wc_permalinks['tag_base'] ) ? trim( $this->wc_permalinks['tag_base'], '/' ) : 'product-tag';
				/* translators: Name of the URL part that precedes every product-tag address, on the plugin's store URLs screen. */
				$return['name'] = __( 'Product Tag Base', 'woocommerce-multilingual' );
				break;

			case 'product_cat':
				$slug           = ! empty( $this->wc_permalinks['category_base'] ) ? trim( $this->wc_permalinks['category_base'], '/' ) : 'product-category';
				/* translators: Name of the URL part that precedes every product-category address, on the plugin's store URLs screen. */
				$return['name'] = __( 'Product Category Base', 'woocommerce-multilingual' );
				break;

			case 'attribute':
				$slug           = trim( $this->wc_permalinks['attribute_base'], '/' );
				/* translators: Name of the URL part that precedes every product-attribute address, on the plugin's store URLs screen. */
				$return['name'] = __( 'Product Attribute Base', 'woocommerce-multilingual' );
				break;

			case 'attribute_slug':
				$slug           = preg_replace( '#^attribute_slug-#', '', $original_base );
				/* translators: Name of the URL part of one product attribute, on the plugin's store URLs screen. */
				$return['name'] = __( 'Attribute Slug', 'woocommerce-multilingual' );
				$string_id      = icl_get_string_id( $slug, Strings::TRANSLATION_DOMAIN, Strings::getStringName( $base, $slug ) );
				break;

			default:
				$endpoints = WC()->query->get_query_vars();
				$slug      = isset( $endpoints[ $base ] ) ? $endpoints[ $base ] : $base;

				/* translators: %s is a slug */
				$return['name'] = sprintf( __( 'Endpoint: %s', 'woocommerce-multilingual' ), $base );
				$string_id      = icl_get_string_id( $slug, $this->get_endpoint_string_context(), $base );
				break;
		}

		$return['original_value'] = $slug;
		if ( ! isset( $string_id ) ) {
			$string_id = icl_get_string_id( $slug, Strings::TRANSLATION_DOMAIN, Strings::getStringName( $base ) );
		}
		$base_translations = icl_get_string_translations_by_id( $string_id );

		$return['translated_base'] = '';
		if ( isset( $base_translations[ $language ] ) ) {
			if ( $base_translations[ $language ]['status'] == ICL_TM_COMPLETE ) {
				$return['translated_base'] = $base_translations[ $language ]['value'];
			} elseif ( $base_translations[ $language ]['status'] == ICL_TM_NEEDS_UPDATE ) {
				$return['translated_base'] = $base_translations[ $language ]['value'];
				$return['needs_update ']   = true;
			}
		}

		return $return;

	}

	private function get_endpoint_string_context() {
		return self::get_endpoints_string_context();
	}

	public static function get_endpoints_string_context(): string {
		return class_exists( WPML_Endpoints_Support::class ) ? WPML_Endpoints_Support::STRING_CONTEXT : self::WC_STRING_CONTEXT;
	}

	public function get_source_slug_language( $base ) {

		if ( $base == 'shop' ) {
			$source_language = $this->sitepress->get_language_for_element( wc_get_page_id( 'shop' ), 'post_page' );
		} elseif ( in_array( $base, [ 'product', WCTaxonomies::TAXONOMY_PRODUCT_CATEGORY, WCTaxonomies::TAXONOMY_PRODUCT_TAG, 'attribute' ] ) ) {
			$source_language = $this->woocommerce_wpml->strings->get_string_language( $base, Strings::TRANSLATION_DOMAIN, Strings::getStringName( $base ) );
		} elseif ( strpos( $base, 'attribute_slug-' ) === 0 ) {
			$slug            = preg_replace( '#^attribute_slug-#', '', $base );
			$source_language = $this->woocommerce_wpml->strings->get_string_language( $base, Strings::TRANSLATION_DOMAIN, Strings::getStringName( 'attribute_slug', $slug ) );
		} else {
			$source_language = $this->woocommerce_wpml->strings->get_string_language( $base, $this->get_endpoint_string_context(), $base );
		}

		return $source_language;
	}

	public function wcml_update_base_translation() {

		$nonce = filter_input( INPUT_POST, 'wcml_nonce', FILTER_SANITIZE_FULL_SPECIAL_CHARS );
		if ( ! $nonce || ! wp_verify_nonce( $nonce, 'wcml_update_base_translation' ) ) {
			die( 'Invalid nonce' );
		}

		WCML_Capabilities::requireCanManageWcmlForAjax();

		$original_base       = $_POST['base'];
		$original_base_value = $_POST['base_value'];
		$base_translation    = wc_sanitize_permalink( trim( $_POST['base_translation'], '/' ) );
		$language            = $_POST['language'];

		if ( $original_base == 'shop' ) {
			$original_shop_id   = wc_get_page_id( 'shop' );
			$translated_shop_id = apply_filters( 'wpml_object_id', $original_shop_id, 'page', false, $language );

			if ( ! is_null( $translated_shop_id ) ) {

				$trnsl_shop_obj = get_post( $translated_shop_id );
				$new_slug       = wp_unique_post_slug( $base_translation, $translated_shop_id, $trnsl_shop_obj->post_status, $trnsl_shop_obj->post_type, $trnsl_shop_obj->post_parent );
				$this->wpdb->update( $this->wpdb->posts, [ 'post_name' => $new_slug ], [ 'ID' => $translated_shop_id ] );

			}
		} else {
			if ( in_array( $original_base, [ 'product', WCTaxonomies::TAXONOMY_PRODUCT_CATEGORY, WCTaxonomies::TAXONOMY_PRODUCT_TAG, 'attribute' ] ) ) {
				$string_id = icl_get_string_id( $original_base_value, Strings::TRANSLATION_DOMAIN, Strings::getStringName( $original_base ) );
			} elseif ( strpos( $original_base, 'attribute_slug-' ) === 0 ) {
				$slug = preg_replace( '#^attribute_slug-#', '', $original_base );
				do_action( 'wpml_register_single_string', Strings::TRANSLATION_DOMAIN, Strings::getStringName( 'attribute_slug', $slug ), $slug );
				$string_id = icl_get_string_id( $original_base_value, Strings::TRANSLATION_DOMAIN, Strings::getStringName( 'attribute_slug', $slug ) );
			} else {
				$string_id = icl_get_string_id( $original_base_value, $this->get_endpoint_string_context(), $original_base );
				if ( ! $string_id && function_exists( 'icl_register_string' ) ) {
					$string_id = icl_register_string( $this->get_endpoint_string_context(), $original_base, $original_base_value );
				}
			}

			icl_add_string_translation( $string_id, $language, $base_translation, ICL_STRING_TRANSLATION_COMPLETE );
		}

		if ( in_array( $original_base, [ WCTaxonomies::TAXONOMY_PRODUCT_CATEGORY, WCTaxonomies::TAXONOMY_PRODUCT_TAG ], true ) ) {
			do_action( 'wpml_activate_slug_translation', $original_base, $original_base_value, WPML_Slug_Translation_Factory::TAX );
		}

		$edit_base = new WCML_Store_URLs_Edit_Base_UI( $original_base, $language, $this->woocommerce_wpml, $this->sitepress );
		$html      = $edit_base->get_view();

		echo json_encode( $html );
		die();

	}

	public function check_wc_tax_url_on_redirect( $redirect_url, $requested_url ) {
		global $wp_query;

		if ( is_tax() ) {
			$original = @parse_url( $requested_url );
			if ( isset( $original['query'] ) ) {
				parse_str( $original['query'], $query_args );
				if ( ( isset( $query_args['product_cat'] ) || isset( $query_args['product_tag'] ) ) && isset( $query_args['lang'] ) ) {
					$obj     = $wp_query->get_queried_object();
					$tax_url = get_term_link( (int) $obj->term_id, $obj->taxonomy );

					return $tax_url;
				}
			}
		}

		return $redirect_url;
	}

	public function translate_query_var_for_product( $public_query_vars ) {

		$product_permalink = $this->woocommerce_wpml->strings->product_permalink_slug();
		$string_language   = $this->woocommerce_wpml->strings->get_string_language( $product_permalink, Strings::TRANSLATION_DOMAIN, Strings::getStringName( 'product' ) );

		if ( $this->sitepress->get_current_language() != $string_language ) {
			$translated_slug = $this->get_translated_product_base_by_lang( false, $product_permalink );

			if ( isset( $_GET[ $translated_slug ] ) ) {
				$buff = $_GET[ $translated_slug ];
				unset( $_GET[ $translated_slug ] );
				$_GET[ $product_permalink ] = $buff;
			}
		}

		return $public_query_vars;
	}

	public function maybe_remove_query_vars_filter() {
		if ( ! is_plugin_active( basename( $this->sitepress->get_wp_api()->constant( 'WPML_ST_PATH' ) ) . '/plugin.php' ) ) {
			remove_filter( 'query_vars', [ $this, 'translate_query_var_for_product' ] );
		}
	}

	public function get_translated_product_base_by_lang( $language = false, $product_slug = false ) {

		if ( ! $language ) {
			$language = $this->sitepress->get_current_language();
		}

		if ( ! $product_slug ) {
			$product_slug = $this->woocommerce_wpml->strings->product_permalink_slug();
		}

		$translated_slug = apply_filters( 'wpml_get_translated_slug', $product_slug, 'product', $language );

		return $translated_slug;
	}

	public function encode_shop_slug( $location ) {
		if ( get_post_type( get_query_var( 'p' ) ) == 'product' ) {
			$language  = $this->sitepress->get_language_for_element( get_query_var( 'p' ), 'post_product' );
			$base_slug = $this->get_translated_product_base_by_lang( $language );

			$location = str_replace( $base_slug, implode( '/', array_map( 'rawurlencode', explode( '/', $base_slug ) ) ), $location );
		}

		return $location;
	}

	public function translate_product_post_type_link( $permalink, $post ) {

		if ( 'product' !== $post->post_type || false === strpos( $permalink, '/uncategorized/' ) ) {
			return $permalink;
		}

		$permalinks = wc_get_permalink_structure();

		if ( preg_match( '`/(.+)(/%product_cat%)`', $permalinks['product_rewrite_slug'] ) ) {
			$find             = 'uncategorized';
			$element_language = $this->sitepress->get_language_for_element( $post->ID, 'post_product' );
			$replace          = $this->woocommerce_wpml->strings->get_translation_from_woocommerce_mo_file( 'slug' . chr( 4 ) . $find, $element_language, false );

			if ( ! is_null( $replace ) ) {
				$permalink = str_replace( $find, $replace, $permalink );
			}
		}

		return $permalink;
	}

	public function translate_product_post_type_link_product_cat_when_display_as_translated( $primary_term, $terms, $post ) {
		if ( 'product' === $post->post_type && WCTaxonomies::isProductCategory( $primary_term->taxonomy ) ) {
			$translated_term_id = apply_filters( 'wpml_object_id', $primary_term->term_id, $primary_term->taxonomy, true );

			return get_term( $translated_term_id, $primary_term->taxonomy );
		}

		return $primary_term;
	}

}
