first commit

This commit is contained in:
2023-09-12 21:41:04 +02:00
commit 3361a7f053
13284 changed files with 2116755 additions and 0 deletions

View File

@@ -0,0 +1,77 @@
<?php
class WPML_Rewrite_Rules_Filter {
/**
* @var array
*/
private $active_languages;
/**
* @var WPML_URL_Filters
*/
private $wpml_url_filters;
/**
* @param array $active_languages
* @param WPML_URL_Filters $wpml_url_filters
*/
public function __construct( $active_languages, $wpml_url_filters = null ) {
$this->active_languages = $active_languages;
if ( ! $wpml_url_filters ) {
global $wpml_url_filters;
}
$this->wpml_url_filters = $wpml_url_filters;
}
/**
* @param string $htaccess_string Content of the .htaccess file
*
* @return string .htaccess file contents with adjusted RewriteBase
*/
public function rid_of_language_param( $htaccess_string ) {
if ( $this->wpml_url_filters->frontend_uses_root() || $this->is_permalink_page() || $this->is_shop_page() ) {
foreach ( $this->active_languages as $lang_code ) {
foreach ( array( '', 'index.php' ) as $base ) {
$htaccess_string = str_replace(
'/' . $lang_code . '/' . $base,
'/' . $base,
$htaccess_string
);
}
}
}
return $htaccess_string;
}
/**
* Check if it is permalink page in admin.
*
* @return bool
*/
private function is_permalink_page() {
return $this->is_admin_screen( 'options-permalink' );
}
/**
* Check if it is WooCommerce shop page in admin.
*
* @return bool
*/
private function is_shop_page() {
return $this->is_admin_screen( 'page' ) && get_option( 'woocommerce_shop_page_id' ) === intval( $_GET['post'] );
}
/**
* Check if it as a certain screen on admin page.
*
* @param string $screen_id
*
* @return bool
*/
private function is_admin_screen( $screen_id ) {
return is_admin() && function_exists( 'get_current_screen' ) && get_current_screen() && get_current_screen()->id === $screen_id;
}
}

View File

@@ -0,0 +1,56 @@
<?php
class WPML_URL_Cached_Converter extends WPML_URL_Converter {
/** @var string[] $cache */
private $cache;
/**
* @param string $url
* @param string|bool $lang_code
*
* @return string
*/
public function convert_url( $url, $lang_code = false ) {
global $sitepress;
if ( ! $lang_code ) {
$lang_code = $sitepress->get_current_language();
}
$negotiation_type = $sitepress->get_setting( 'language_negotiation_type' );
$skip_convert_url_string = $this->get_strategy()->skip_convert_url_string( $url, $lang_code );
$cache_key_args = array( $url, $lang_code, $negotiation_type, $skip_convert_url_string );
$cache_key = md5( wp_json_encode( $cache_key_args ) );
$cache_group = 'convert_url';
$cache_found = false;
$cache = new WPML_WP_Cache( $cache_group );
$new_url = $cache->get( $cache_key, $cache_found );
if ( ! $cache_found ) {
$new_url = parent::convert_url( $url, $lang_code );
$cache->set( $cache_key, $new_url );
}
return $new_url;
}
/**
* @param string $url
*
* @return string
*/
public function get_language_from_url( $url ) {
if ( isset( $this->cache[ $url ] ) ) {
return $this->cache[ $url ];
}
$lang = parent::get_language_from_url( $url );
$this->cache[ $url ] = $lang;
return $lang;
}
}

View File

@@ -0,0 +1,51 @@
<?php
class WPML_URL_Converter_CPT {
/**
* @var WPML_Slash_Management
*/
private $slash_helper;
/**
* @param WPML_Slash_Management $slash_helper
*/
public function __construct( WPML_Slash_Management $slash_helper = null ) {
if ( ! $slash_helper ) {
$slash_helper = new WPML_Slash_Management();
}
$this->slash_helper = $slash_helper;
}
/**
* Adjusts the CPT archive slug for possible slug translations from ST.
*
* @param string $link
* @param string $post_type
* @param null|string $language_code
*
* @return string
*/
public function adjust_cpt_slug_in_url( $link, $post_type, $language_code = null ) {
$post_type_object = get_post_type_object( $post_type );
if ( isset( $post_type_object->rewrite ) ) {
$slug = trim( $post_type_object->rewrite['slug'], '/' );
} else {
$slug = $post_type_object->name;
}
$translated_slug = apply_filters( 'wpml_get_translated_slug', $slug, $post_type, $language_code );
if ( is_string( $translated_slug ) ) {
$link_parts = explode( '?', $link, 2 );
$pattern = '#\/' . preg_quote( $slug, '#' ) . '\/#';
$link_new = trailingslashit( preg_replace( $pattern, '/' . $translated_slug . '/', trailingslashit( $link_parts[0] ), 1 ) );
$link = $this->slash_helper->match_trailing_slash_to_reference( $link_new, $link_parts[0] );
$link = isset( $link_parts[1] ) ? $link . '?' . $link_parts[1] : $link;
}
return $link;
}
}

View File

@@ -0,0 +1,158 @@
<?php
class WPML_URL_Converter_Factory {
/**
* @var array
*/
private $settings;
/**
* @var string
*/
private $default_lang_code;
/**
* @var array
*/
private $active_language_codes;
/**
* @var WPML_Resolve_Object_Url_Helper_Factory
*/
private $object_url_helper_factory;
/** @var WPML_URL_Converter */
private static $previous_url_converter;
const SUBDIR = 1;
const DOMAIN = 2;
/**
* @param array $settings
* @param string $default_lang_code
* @param array $active_language_codes
*/
public function __construct( $settings, $default_lang_code, $active_language_codes ) {
$this->settings = $settings;
$this->default_lang_code = $default_lang_code;
$this->active_language_codes = $active_language_codes;
}
public static function remove_previous_hooks() {
if ( self::$previous_url_converter ) {
self::$previous_url_converter->get_strategy()->remove_hooks();
}
}
/**
* @return WPML_Resolve_Object_Url_Helper_Factory
*/
public function get_object_url_helper_factory() {
if ( ! $this->object_url_helper_factory ) {
$this->object_url_helper_factory = new WPML_Resolve_Object_Url_Helper_Factory();
}
return $this->object_url_helper_factory;
}
/**
* @param WPML_Resolve_Object_Url_Helper_Factory $factory
*/
public function set_object_url_helper_factory( WPML_Resolve_Object_Url_Helper_Factory $factory ) {
$this->object_url_helper_factory = $factory;
}
/**
* @param int $url_type
*
* @return WPML_URL_Converter
*/
public function create( $url_type ) {
switch ( $url_type ) {
case self::SUBDIR:
$wpml_url_converter = $this->create_subdir_converter();
break;
case self::DOMAIN:
$wpml_url_converter = $this->create_domain_converter();
break;
default:
$wpml_url_converter = $this->create_parameter_converter();
}
$home_url = new WPML_URL_Converter_Url_Helper();
$wpml_url_converter->set_url_helper( $home_url );
$wpml_url_converter->get_strategy()->add_hooks();
self::$previous_url_converter = $wpml_url_converter;
return $wpml_url_converter;
}
/**
* @return WPML_URL_Cached_Converter
*/
private function create_subdir_converter() {
$dir_default = false;
if ( ! isset( $this->settings['urls'] ) ) {
$this->settings['urls'] = array();
} else {
if ( isset( $this->settings['urls']['directory_for_default_language'] ) ) {
$dir_default = $this->settings['urls']['directory_for_default_language'];
}
}
$strategy = new WPML_URL_Converter_Subdir_Strategy( $dir_default, $this->default_lang_code, $this->active_language_codes, $this->settings['urls'] );
return new WPML_URL_Cached_Converter(
$strategy,
$this->get_object_url_helper_factory()->create(),
$this->default_lang_code,
$this->active_language_codes
);
}
/**
* @return WPML_URL_Cached_Converter
*/
private function create_domain_converter() {
$domains = isset( $this->settings['language_domains'] ) ? $this->settings['language_domains'] : array();
$wpml_wp_api = new WPML_WP_API();
$strategy = new WPML_URL_Converter_Domain_Strategy( $domains, $this->default_lang_code, $this->active_language_codes );
$wpml_url_converter = new WPML_URL_Cached_Converter(
$strategy,
$this->get_object_url_helper_factory()->create(),
$this->default_lang_code,
$this->active_language_codes
);
$wpml_fix_url_domain = new WPML_Lang_Domain_Filters(
$wpml_url_converter,
$wpml_wp_api,
new WPML_Debug_BackTrace( null, 10 )
);
$wpml_fix_url_domain->add_hooks();
$xdomain_data_parser = new WPML_XDomain_Data_Parser( $this->settings, new WPML_Data_Encryptor() );
$xdomain_data_parser->init_hooks();
return $wpml_url_converter;
}
/**
* @return WPML_URL_Cached_Converter
*/
private function create_parameter_converter() {
$strategy = new WPML_URL_Converter_Parameter_Strategy( $this->default_lang_code, $this->active_language_codes );
$wpml_url_converter = new WPML_URL_Cached_Converter(
$strategy,
$this->get_object_url_helper_factory()->create(),
$this->default_lang_code,
$this->active_language_codes
);
$filters = new WPML_Lang_Parameter_Filters();
$filters->add_hooks();
return $wpml_url_converter;
}
}

View File

@@ -0,0 +1,235 @@
<?php
/**
* Class WPML_URL_Converter
*
* @package wpml-core
* @subpackage url-handling
*/
use WPML\SuperGlobals\Server;
use WPML\UrlHandling\WPLoginUrlConverter;
class WPML_URL_Converter {
/**
* @var IWPML_URL_Converter_Strategy
*/
private $strategy;
/**
* @var string
*/
protected $default_language;
/**
* @var string[]
*/
protected $active_languages;
/**
* @var WPML_URL_Converter_Url_Helper
*/
protected $home_url_helper;
/**
* @var WPML_URL_Converter_Lang_Param_Helper
*/
protected $lang_param;
/**
* @var WPML_Slash_Management
*/
protected $slash_helper;
/**
* @var WPML_Resolve_Object_Url_Helper
*/
protected $object_url_helper;
/**
* @param IWPML_URL_Converter_Strategy $strategy
* @param WPML_Resolve_Object_Url_Helper $object_url_helper
* @param string $default_language
* @param array<string> $active_languages
*/
public function __construct(
IWPML_URL_Converter_Strategy $strategy,
WPML_Resolve_Object_Url_Helper $object_url_helper,
$default_language,
$active_languages
) {
$this->strategy = $strategy;
$this->object_url_helper = $object_url_helper;
$this->default_language = $default_language;
$this->active_languages = $active_languages;
$this->lang_param = new WPML_URL_Converter_Lang_Param_Helper( $active_languages );
$this->slash_helper = new WPML_Slash_Management();
}
/**
* @return IWPML_URL_Converter_Strategy
*/
public function get_strategy() {
return $this->strategy;
}
/**
* @param WPML_URL_Converter_Url_Helper $url_helper
*/
public function set_url_helper( WPML_URL_Converter_Url_Helper $url_helper ) {
$this->home_url_helper = $url_helper;
if ( $this->strategy instanceof WPML_URL_Converter_Abstract_Strategy ) {
$this->strategy->set_url_helper( $url_helper );
}
}
/**
* @return WPML_URL_Converter_Url_Helper
*/
public function get_url_helper() {
if ( ! $this->home_url_helper ) {
$this->home_url_helper = new WPML_URL_Converter_Url_Helper();
}
return $this->home_url_helper;
}
public function get_abs_home() {
return $this->get_url_helper()->get_abs_home();
}
/**
* @param WPML_URL_Converter_Lang_Param_Helper $lang_param_helper
*/
public function set_lang_param_helper( WPML_URL_Converter_Lang_Param_Helper $lang_param_helper ) {
$this->lang_param = $lang_param_helper;
}
/**
* @param WPML_Slash_Management $slash_helper
*/
public function set_slash_helper( WPML_Slash_Management $slash_helper ) {
$this->slash_helper = $slash_helper;
}
public function get_default_site_url() {
return $this->get_url_helper()->get_unfiltered_home_option();
}
/**
* Scope of this function:
* 1. Convert the home URL in the specified language depending on language negotiation:
* 1. Add a language directory
* 2. Change the domain
* 3. Add a language parameter
* 2. If the requested URL is equal to the current URL, the URI will be adapted
* with potential slug translations for:
* - single post slugs
* - taxonomy term slug
*
* WARNING: The URI slugs won't be translated for arbitrary URL (not the current one)
*
* @param string $url
* @param bool $lang_code
*
* @return bool|mixed|string
*/
public function convert_url( $url, $lang_code = false ) {
if ( ! $url ) {
return $url;
}
global $sitepress;
$new_url = false;
if ( ! $lang_code ) {
$lang_code = $sitepress->get_current_language();
}
$language_from_url = $this->get_language_from_url( $url );
if ( $language_from_url === $lang_code || 'all' === $lang_code ) {
$new_url = $url;
} else {
if ( $this->can_resolve_object_url( $url ) ) {
$new_url = $this->object_url_helper->resolve_object_url( $url, $lang_code );
}
if ( false === $new_url ) {
$new_url = $this->strategy->convert_url_string( $url, $lang_code );
}
}
return $new_url;
}
/**
* Takes a URL and returns the language of the document it points at
*
* @param string $url
* @return string
*/
public function get_language_from_url( $url ) {
$http_referer_factory = new WPML_URL_HTTP_Referer_Factory();
$http_referer = $http_referer_factory->create();
$url = $http_referer->get_url( $url );
$language = $this->lang_param->lang_by_param( $url ) ?: $this->get_strategy()->get_lang_from_url_string( $url );
/**
* Filters language code fetched from the current URL and allows to rewrite
* the language to set on front-end
*
* @param string $language language fetched from the current URL
* @param string $url current URL.
*/
$language = apply_filters( 'wpml_get_language_from_url', $language, $url );
return $this->get_strategy()->validate_language( $language, $url );
}
/**
* @param string $url
* @param string $language
*
* @return string
*/
public function get_home_url_relative( $url, $language ) {
return $this->get_strategy()->get_home_url_relative( $url, $language );
}
/**
* @param SitePress $sitepress
*
* @return WPLoginUrlConverter|null
*/
public function get_wp_login_url_converter( $sitepress ) {
return $this->strategy->use_wp_login_url_converter()
? new WPLoginUrlConverter( $sitepress, $this )
: null;
}
/**
* @param string $url
*
* @return bool
*/
private function can_resolve_object_url( $url ) {
$request_uri = isset( $_SERVER['REQUEST_URI'] ) ? $_SERVER['REQUEST_URI'] : '';
$server_name = strpos( $request_uri, '/' ) === 0
? untrailingslashit( Server::getServerName() ) : trailingslashit( Server::getServerName() );
$request_url = stripos( get_option( 'siteurl' ), 'https://' ) === 0
? 'https://' . $server_name . $request_uri : 'http://' . $server_name . $request_uri;
$is_request_url = trailingslashit( $request_url ) === trailingslashit( $url );
$is_home_url = trailingslashit( $this->get_url_helper()->get_abs_home() ) === trailingslashit( $url );
$is_home_url_filter = current_filter() === 'home_url';
return $is_request_url && ! $is_home_url && ! $is_home_url_filter;
}
/** @return WPML_URL_Converter */
public static function getGlobalInstance() {
global $wpml_url_converter;
return $wpml_url_converter;
}
}

View File

@@ -0,0 +1,167 @@
<?php
class WPML_Lang_Domain_Filters {
private $wpml_url_converter;
private $wpml_wp_api;
private $debug_backtrace;
private $domains = array();
/**
* WPML_Lang_Domain_Filters constructor.
*
* @param \WPML_URL_Converter $wpml_url_converter
* @param \WPML_WP_API $wpml_wp_api
*/
public function __construct(
WPML_URL_Converter $wpml_url_converter,
WPML_WP_API $wpml_wp_api,
WPML_Debug_BackTrace $debug_backtrace
) {
$this->wpml_url_converter = $wpml_url_converter;
$this->wpml_wp_api = $wpml_wp_api;
$this->debug_backtrace = $debug_backtrace;
}
public function add_hooks() {
add_filter( 'upload_dir', array( $this, 'upload_dir_filter_callback' ) );
add_filter( 'stylesheet_uri', array( $this, 'convert_url' ) );
add_filter( 'option_siteurl', array( $this, 'siteurl_callback' ) );
add_filter( 'content_url', array( $this, 'siteurl_callback' ) );
add_filter( 'plugins_url', array( $this, 'siteurl_callback' ) );
add_filter( 'login_url', array( $this, 'convert_url' ) );
add_filter( 'logout_url', array( $this, 'convert_logout_url' ) );
add_filter( 'admin_url', array( $this, 'admin_url_filter' ), 10, 2 );
add_filter( 'login_redirect', array( $this, 'convert_url' ), 1, 3 );
}
/**
* @param string $url
*
* @return string
*/
public function convert_url( $url ) {
return $this->wpml_url_converter->convert_url( $url );
}
/**
* @param array $upload_dir
*
* @return array
*/
public function upload_dir_filter_callback( $upload_dir ) {
$convertWithMatchingTrailingSlash = function ( $url ) {
$hasTrailingSlash = '/' === substr( $url, -1 );
$newUrl = $this->wpml_url_converter->convert_url( $url );
return $hasTrailingSlash ? trailingslashit( $newUrl ) : untrailingslashit( $newUrl );
};
$upload_dir['url'] = $convertWithMatchingTrailingSlash( $upload_dir['url'] );
$upload_dir['baseurl'] = $convertWithMatchingTrailingSlash( $upload_dir['baseurl'] );
return $upload_dir;
}
/**
* @param string $url
*
* @return string
*/
public function siteurl_callback( $url ) {
$getting_network_site_url = $this->debug_backtrace->is_function_in_call_stack( 'get_admin_url' ) && is_multisite();
if ( ! $this->debug_backtrace->is_function_in_call_stack( 'get_home_path', false ) && ! $getting_network_site_url ) {
$parsed_url = wpml_parse_url( $url );
$host = is_array( $parsed_url ) && isset( $parsed_url['host'] );
if ( $host && isset( $_SERVER['HTTP_HOST'] ) && $_SERVER['HTTP_HOST'] ) {
$domain_from_global = $this->get_host_from_HTTP_HOST();
if ( $domain_from_global ) {
$url = str_replace( $parsed_url['host'], $domain_from_global, $url );
}
}
}
return $url;
}
/**
* @return string
*/
private function get_host_from_HTTP_HOST() {
$host = $_SERVER['HTTP_HOST'];
if ( false !== strpos( $_SERVER['HTTP_HOST'], ':' ) ) {
$host = explode( ':', $_SERVER['HTTP_HOST'] );
$host = $host[0];
}
return $this->is_host_valid( $host ) ? $host : null;
}
/**
* @param string $host
*
* @return bool
*/
private function is_host_valid( $host ) {
$valid = false;
foreach ( $this->get_domains() as $domain ) {
if ( $domain === $host ) {
$valid = true;
break;
}
}
return $valid;
}
/**
* @return array
*/
private function get_domains() {
if ( ! $this->domains ) {
$this->domains = wpml_get_setting( 'language_domains' );
$home_parsed = wp_parse_url( $this->wpml_url_converter->get_abs_home() );
$this->domains[] = $home_parsed['host'];
}
return $this->domains;
}
/**
* @param string $url
* @param string $path
*
* @return string
*/
public function admin_url_filter( $url, $path ) {
if ( ( strpos( $url, 'http://' ) === 0
|| strpos( $url, 'https://' ) === 0 )
&& 'admin-ajax.php' === $path && $this->wpml_wp_api->is_front_end()
) {
global $sitepress;
$url = $this->wpml_url_converter->convert_url( $url, $sitepress->get_current_language() );
}
return $url;
}
/**
* Convert logout url only for front-end.
*
* @param string $logout_url
*
* @return string
*/
public function convert_logout_url( $logout_url ) {
if ( $this->wpml_wp_api->is_front_end() ) {
$logout_url = $this->wpml_url_converter->convert_url( $logout_url );
}
return $logout_url;
}
}

View File

@@ -0,0 +1,63 @@
<?php
class WPML_Lang_Parameter_Filters {
public function add_hooks() {
add_filter( 'request', array( $this, 'request_filter' ) );
add_filter( 'get_pagenum_link', array( $this, 'paginated_url_filter' ) );
add_filter( 'wp_link_pages_link', array( $this, 'paginated_link_filter' ) );
}
public function request_filter( $request ) {
// This is required so that home page detection works for other languages.
if ( ! defined( 'WP_ADMIN' ) && isset( $request['lang'] ) ) {
unset( $request['lang'] );
}
return $request;
}
/**
* Filters the pagination links on taxonomy archives to properly have the language parameter after the URI.
*
* @param string $url
*
* @return string
*/
public function paginated_url_filter( $url ) {
$url = urldecode( $url );
$parts = explode( '?', $url );
$last_part = count( $parts ) > 2 ? array_pop( $parts ) : '';
$url = join( '?', $parts );
$url = preg_replace( '#(.+?)(/\?|\?)(.*?)(/.+?$)$#', '$1$4$5?$3', $url );
$url = preg_replace( '#(\?.+)(%2F|\/)$#', '$1', $url );
if ( '' !== $last_part && strpos( $url, '?' . $last_part ) === false ) {
$url .= '&' . $last_part;
}
$parts = explode( '?', $url );
if ( isset( $parts[1] ) ) {
// Maybe remove duplicated lang param
$params = array();
parse_str( $parts[1], $params );
$url = $parts[0] . '?' . build_query( $params );
}
return $url;
}
/**
* Filters the pagination links on paginated posts and pages, acting on the links html
* output containing the anchor tag the link is a property of.
*
* @param string $link_html
*
* @return string
*
* @hook wp_link_pages_link
*/
public function paginated_link_filter( $link_html ) {
return preg_replace( '#"([^"].+?)(/\?|\?)([^/]+)(/[^"]+)"#', '"$1$4?$3"', $link_html );
}
}

View File

@@ -0,0 +1,15 @@
<?php
class WPML_Tax_Permalink_Filters_Factory implements IWPML_Frontend_Action_Loader, IWPML_Backend_Action_Loader {
public function create() {
global $wpml_url_converter, $sitepress;
return new WPML_Tax_Permalink_Filters(
$wpml_url_converter,
new WPML_WP_Cache_Factory(),
new WPML_Translation_Element_Factory( $sitepress ),
WPML_Get_LS_Languages_Status::get_instance()
);
}
}

View File

@@ -0,0 +1,96 @@
<?php
class WPML_Tax_Permalink_Filters implements IWPML_Action {
/** @var WPML_Translation_Element_Factory */
private $term_element_factory;
/** @var WPML_URL_Converter */
private $url_converter;
/** @var WPML_WP_Cache_Factory $cache_factory */
private $cache_factory;
/** @var WPML_Get_LS_Languages_Status */
private $ls_languages_status;
public function __construct(
WPML_URL_Converter $url_converter,
WPML_WP_Cache_Factory $cache_factory,
WPML_Translation_Element_Factory $term_element_factory,
WPML_Get_LS_Languages_Status $ls_language_status
) {
$this->term_element_factory = $term_element_factory;
$this->url_converter = $url_converter;
$this->cache_factory = $cache_factory;
$this->ls_languages_status = $ls_language_status;
}
public function add_hooks() {
add_filter( 'term_link', array( $this, 'cached_filter_tax_permalink' ), 1, 3 );
}
/**
* @param string $permalink
* @param int|\WP_Term|\stdClass $tag
* @param string $taxonomy
*
* @return string
*/
public function cached_filter_tax_permalink( $permalink, $tag, $taxonomy ) {
$tag = is_object( $tag ) ? $tag : get_term( $tag, $taxonomy );
$tag_id = $tag ? $tag->term_id : 0;
$cache = $this->cache_factory->create_cache_item( 'icl_tax_permalink_filter', array(
$tag_id,
$taxonomy,
$this->is_link_for_language_switcher()
) );
if ( $cache->exists() ) {
return $cache->get();
}
$permalink = $this->filter_tax_permalink( $permalink, $tag_id );
$cache->set( $permalink );
return $permalink;
}
/**
* Filters the permalink pointing at a taxonomy archive to correctly reflect the language of its underlying term
*
* @param string $permalink url pointing at a term's archive
* @param int $tag_id
*
* @return string
*/
private function filter_tax_permalink( $permalink, $tag_id ) {
if ( $tag_id ) {
$term_element = $this->term_element_factory->create( $tag_id, 'term' );
if ( ! $this->is_display_as_translated_and_in_default_lang( $term_element )
|| $this->is_link_for_language_switcher()
) {
$term_language = $term_element->get_language_code();
if ( (bool) $term_language ) {
$permalink = $this->url_converter->convert_url( $permalink, $term_language );
}
}
}
return $permalink;
}
private function is_display_as_translated_and_in_default_lang( WPML_Translation_Element $element ) {
return $element->is_display_as_translated()
&& $element->is_in_default_language();
}
private function is_link_for_language_switcher() {
return $this->ls_languages_status->is_getting_ls_languages();
}
}

View File

@@ -0,0 +1,109 @@
<?php
class WPML_URL_Converter_Lang_Param_Helper {
/**
* @var array
*/
private static $cache = array();
/**
* @var array
*/
private $active_languages;
/**
* @param array $active_languages
*/
public function __construct( array $active_languages ) {
$this->active_languages = $active_languages;
}
/**
*
* @param string $url
* @param bool $only_admin If set to true only language parameters on Admin Screen URLs will be recognized. The
* function will return null for non-Admin Screens.
*
* @return null|string Language code
*/
public function lang_by_param( $url, $only_admin = true ) {
if ( isset( self::$cache[ $url ] ) ) {
return self::$cache[ $url ];
}
$lang = $this->extract_lang_param_from_url( $url, $only_admin );
self::$cache[ $url ] = $lang;
return $lang;
}
/**
* @param string $url
* @param bool $only_admin
*
* @return string|null
*/
private function extract_lang_param_from_url( $url, $only_admin ) {
$url = wpml_strip_subdir_from_url( $url );
$url_query_parts = wpml_parse_url( $url );
$url_query = $this->has_query_part( $only_admin, $url_query_parts ) ? untrailingslashit( $url_query_parts['query'] ) : null;
if ( null !== $url_query ) {
parse_str( $url_query, $vars );
if ( $this->can_retrieve_lang_from_query( $only_admin, $vars ) ) {
return $vars['lang'];
}
}
return null;
}
/**
* @param bool $only_admin
* @param array $url_query_parts
*
* @return bool
*/
private function has_query_part( $only_admin, $url_query_parts ) {
if ( ! isset( $url_query_parts['query'] ) ) {
return false;
}
if ( false === $only_admin ) {
return true;
}
if ( ! isset( $url_query_parts['path'] ) ) {
return false;
}
if ( false === strpos( $url_query_parts['path'], '/wp-admin' ) ) {
return false;
}
return true;
}
/**
* @param bool $only_admin
* @param array $vars
*
* @return bool
*/
private function can_retrieve_lang_from_query( $only_admin, $vars ) {
if ( ! isset( $vars['lang'] ) ) {
return false;
}
if ( $only_admin && 'all' === $vars['lang'] ) {
return true;
}
if ( in_array( $vars['lang'], $this->active_languages, true ) ) {
return true;
}
return false;
}
}

View File

@@ -0,0 +1,99 @@
<?php
class WPML_URL_Converter_Url_Helper {
/**
* @var wpdb
*/
private $wpdb;
/**
* @var WPML_Include_Url
*/
private $wpml_include_url_filter;
/**
* @var string
*/
private $absolute_home;
/**
*
* @param wpdb $wpdb
* @param WPML_Include_Url $wpml_include_url_filter
*/
public function __construct( wpdb $wpdb = null, WPML_Include_Url $wpml_include_url_filter = null ) {
if ( ! $wpdb ) {
global $wpdb;
}
if ( ! $wpml_include_url_filter ) {
global $wpml_include_url_filter;
}
$this->wpdb = $wpdb;
$this->wpml_include_url_filter = $wpml_include_url_filter;
}
/**
* Returns the unfiltered home_url by directly retrieving it from wp_options.
*
* @return string
*/
public function get_abs_home() {
if ( ! $this->absolute_home ) {
$is_multisite = is_multisite();
if ( ! $is_multisite && defined( 'WP_HOME' ) ) {
$this->absolute_home = WP_HOME;
} elseif ( $is_multisite && ! is_main_site() ) {
$protocol = preg_match( '/^(https)/', get_option( 'home' ) ) === 1 ? 'https://' : 'http://';
$sql = "
SELECT CONCAT(b.domain, b.path)
FROM {$this->wpdb->blogs} b
WHERE blog_id = {$this->wpdb->blogid}
LIMIT 1
";
$this->absolute_home = $protocol . $this->wpdb->get_var( $sql );
} else {
$this->absolute_home = $this->get_unfiltered_home_option();
}
}
return apply_filters( 'wpml_url_converter_get_abs_home', $this->absolute_home );
}
/**
* Checks if a $url points to a WP Admin screen.
*
* @param string $url
* @return bool True if the input $url points to an admin screen.
*/
public function is_url_admin( $url ) {
$url_query_parts = wpml_parse_url( strpos( $url, 'http' ) === false ? 'http://' . $url : $url );
return isset( $url_query_parts['path'] )
&& strpos( wpml_strip_subdir_from_url( $url_query_parts['path'] ), '/wp-admin' ) === 0;
}
/**
* Returns the unfiltered home option from the database.
*
* @uses \WPML_Include_Url::get_unfiltered_home in case the $wpml_include_url_filter global is loaded
*
* @return string
*/
public function get_unfiltered_home_option() {
if ( $this->wpml_include_url_filter ) {
return $this->wpml_include_url_filter->get_unfiltered_home();
} else {
$sql = "
SELECT option_value
FROM {$this->wpdb->options}
WHERE option_name = 'home'
LIMIT 1
";
return $this->wpdb->get_var( $sql );
}
}
}

View File

@@ -0,0 +1,116 @@
<?php
abstract class WPML_URL_Converter_Abstract_Strategy implements IWPML_URL_Converter_Strategy {
protected $absolute_home;
protected $default_language;
protected $active_languages;
protected $cache;
/**
* @var WPML_URL_Converter_Url_Helper
*/
protected $url_helper;
/**
* @var WPML_URL_Converter_Lang_Param_Helper
*/
protected $lang_param;
/**
* @var WPML_Slash_Management
*/
protected $slash_helper;
/**
* @var WP_Rewrite
*/
protected $wp_rewrite;
/**
* @param string $default_language
* @param array<string> $active_languages
* @param WP_Rewrite|null $wp_rewrite
* @param WPML_Slash_Management|null $splash_helper
*/
public function __construct( $default_language, $active_languages, $wp_rewrite = null, $splash_helper = null ) {
$this->default_language = $default_language;
$this->active_languages = $active_languages;
$this->lang_param = new WPML_URL_Converter_Lang_Param_Helper( $active_languages );
$this->slash_helper = $splash_helper ?: new WPML_Slash_Management();
if ( ! $wp_rewrite ) {
global $wp_rewrite;
}
$this->wp_rewrite = $wp_rewrite;
}
public function validate_language( $language, $url ) {
return in_array( $language, $this->active_languages, true )
|| 'all' === $language && $this->get_url_helper()->is_url_admin( $url ) ? $language : $this->get_default_language();
}
/**
* @param WPML_URL_Converter_Url_Helper $url_helper
*/
public function set_url_helper( WPML_URL_Converter_Url_Helper $url_helper ) {
$this->url_helper = $url_helper;
}
/**
* @return WPML_URL_Converter_Url_Helper
*/
public function get_url_helper() {
if ( ! $this->url_helper ) {
$this->url_helper = new WPML_URL_Converter_Url_Helper();
}
return $this->url_helper;
}
/**
* @param WPML_URL_Converter_Lang_Param_Helper $lang_param
*/
public function set_lang_param( WPML_URL_Converter_Lang_Param_Helper $lang_param ) {
$this->lang_param = $lang_param;
}
/**
* @param WPML_Slash_Management $slash_helper
*/
public function set_slash_helper( WPML_Slash_Management $slash_helper ) {
$this->slash_helper = $slash_helper;
}
private function get_default_language() {
if ( $this->default_language ) {
return $this->default_language;
} else {
return icl_get_setting( 'default_language' );
}
}
public function fix_trailingslashit( $source_url ) {
return $source_url;
}
public function skip_convert_url_string( $source_url, $lang_code ) {
/**
* Allows plugins to skip url conversion.
*
* @since 4.3
*
* @param bool
* @param string $source_url
* @param string $lang_code
* @return bool
*/
return apply_filters( 'wpml_skip_convert_url_string', false, $source_url, $lang_code );
}
public function use_wp_login_url_converter() {
return false;
}
}

View File

@@ -0,0 +1,146 @@
<?php
use \WPML\SuperGlobals\Server;
class WPML_URL_Converter_Domain_Strategy extends WPML_URL_Converter_Abstract_Strategy {
/** @var string[] $domains */
private $domains = array();
/**
* @param array $domains
* @param string $default_language
* @param array $active_languages
*/
public function __construct(
$domains,
$default_language,
$active_languages
) {
parent::__construct( $default_language, $active_languages );
$domains = array_map( 'untrailingslashit', $domains );
$this->domains = array_map( array( $this, 'strip_protocol' ), $domains );
if ( isset( $this->domains[ $default_language ] ) ) {
unset( $this->domains[ $default_language ] );
}
}
public function add_hooks() {
add_filter( 'rest_url', [ $this, 'convertRestUrlToCurrentDomain' ], 10, 4 );
}
public function remove_hooks() {
remove_filter( 'rest_url', [ $this, 'convertRestUrlToCurrentDomain' ] );
}
/**
* Filter REST url to avoid CORS error in Gutenberg.
* https://onthegosystems.myjetbrains.com/youtrack/issue/wpmlcore-7022
*
* @param string $url REST URL.
* @param string $path REST route.
* @param int $blog_id Blog ID.
* @param string $scheme Sanitization scheme.
*
* @return string
*/
public function convertRestUrlToCurrentDomain( $url, $path, $blog_id, $scheme ) {
$url_parts = $this->parse_domain_and_subdir( $url );
$url_parts['host'] = Server::getServerName();
$url = http_build_url( $url_parts );
return $url;
}
public function get_lang_from_url_string( $url ) {
$url = $this->strip_protocol( $url );
if ( strpos( $url, '?' ) ) {
$parts = explode( '?', $url );
$url = $parts[0];
}
foreach ( $this->domains as $code => $domain ) {
if ( $domain && strpos( trailingslashit( $url ), trailingslashit( $domain ) ) === 0 ) {
return $code;
}
}
return null;
}
public function convert_url_string( $source_url, $lang ) {
$original_source_url = untrailingslashit( $source_url );
if ( is_admin() && $this->get_url_helper()->is_url_admin( $original_source_url ) ) {
return $original_source_url;
}
return $this->convert_url( $source_url, $lang );
}
public function convert_admin_url_string( $source_url, $lang ) {
return $this->convert_url( $source_url, $lang );
}
private function convert_url( $source_url, $lang ) {
if ( $this->skip_convert_url_string( $source_url, $lang ) ) {
return $source_url;
}
$base_url = isset( $this->domains[ $lang ] ) ? $this->domains[ $lang ] : $this->get_url_helper()->get_abs_home();
$base_url_parts = $this->parse_domain_and_subdir( $base_url );
$url_parts = $this->parse_domain_and_subdir( $source_url );
if ( isset( $base_url_parts['host'] ) ) {
$url_parts['host'] = $base_url_parts['host'];
}
$converted_url = http_build_url( $url_parts );
return $this->slash_helper->maybe_user_trailingslashit( $converted_url );
}
/**
* @param string $base_url
*
* @return array
*/
private function parse_domain_and_subdir( $base_url ) {
$url_parts = wpml_parse_url( $base_url );
return is_array( $url_parts ) ?
$this->slash_helper->parse_missing_host_from_path( $url_parts ) :
[];
}
/**
* @param string $url
* @param string $language
*
* @return string
*/
public function get_home_url_relative( $url, $language ) {
return $url;
}
/**
* @param string $url
*
* @return array|string
*/
private function strip_protocol( $url ) {
$url_parts = wpml_parse_url( $url );
if ( is_array( $url_parts ) ) {
$url_parts = $this->slash_helper->parse_missing_host_from_path( $url_parts );
unset( $url_parts['scheme'] );
return http_build_url( $url_parts );
} else {
return preg_replace( '/^https?:\/\//', '', $url );
}
}
}

View File

@@ -0,0 +1,109 @@
<?php
class WPML_URL_Converter_Parameter_Strategy extends WPML_URL_Converter_Abstract_Strategy {
public function add_hooks() {
}
public function remove_hooks() {
}
public function get_lang_from_url_string( $url ) {
return $this->lang_param->lang_by_param( $url, false );
}
public function convert_url_string( $source_url, $lang_code ) {
if ( $this->skip_convert_url_string( $source_url, $lang_code ) ) {
return $source_url;
}
if ( ! $lang_code || $lang_code === $this->default_language ) {
$lang_code = '';
}
$url_parts = wpml_parse_url( $source_url );
if ( ! is_array( $url_parts ) ) {
$url_parts = [];
}
// This is required for logout url, the parameter comes urlencoded in the URI generated by WordPress.
// If we don't decode it first, it will be misinterpreted by browsers when combined with regular parameters.
if ( isset( $url_parts['query'] ) ) {
$url_parts['query'] = str_replace( '&amp;_wpnonce', '&_wpnonce', $url_parts['query'] );
}
$query_args = $this->get_query_args( $url_parts );
if ( $lang_code ) {
$query_args['lang'] = $lang_code;
} else {
unset( $query_args['lang'] );
}
$url_parts['query'] = http_build_query( $query_args );
$converted_url = http_build_url( $url_parts );
return $this->slash_helper->maybe_user_trailingslashit( $converted_url );
}
public function convert_admin_url_string( $source_url, $lang ) {
return $this->convert_url_string( $source_url, $lang );
}
/**
* @param array $url_parts
*
* @return array
*/
private function get_query_args( array $url_parts ) {
$query = isset( $url_parts['query'] ) ? $url_parts['query'] : '';
$query = str_replace( '?', '&', $query );
parse_str( $query, $query_args );
return $query_args;
}
/**
* @param string $url
* @param string $language
*
* @return string
*/
public function get_home_url_relative( $url, $language ) {
if ( $language === $this->default_language ) {
$language = '';
}
if ( $language ) {
return add_query_arg( 'lang', $language, $url );
} else {
return $url;
}
}
/**
* @param string $source_url
*
* @return string
*/
public function fix_trailingslashit( $source_url ) {
$query = wpml_parse_url( $source_url, PHP_URL_QUERY );
if ( ! empty( $query ) ) {
$source_url = str_replace( '?' . $query, '', $source_url );
}
$source_url = $this->slash_helper->maybe_user_trailingslashit( $source_url );
if ( ! empty( $query ) ) {
$source_url .= '?' . untrailingslashit( $query );
}
return $source_url;
}
public function use_wp_login_url_converter() {
return true;
}
}

View File

@@ -0,0 +1,252 @@
<?php
class WPML_URL_Converter_Subdir_Strategy extends WPML_URL_Converter_Abstract_Strategy {
/** @var bool */
private $use_directory_for_default_lang;
/** @var array copy of $sitepress->get_settings( 'urls' ) */
private $urls_settings;
/** @var string|bool */
private $root_url;
/** @var array map of wpml codes to custom codes*/
private $language_codes_map;
private $language_codes_reverse_map;
/** @var bool */
private $is_rest_request;
/**
* @param bool $use_directory_for_default_lang
* @param string $default_language
* @param array $active_languages
* @param array $urls_settings
*/
public function __construct(
$use_directory_for_default_lang,
$default_language,
$active_languages,
$urls_settings
) {
parent::__construct( $default_language, $active_languages );
$this->use_directory_for_default_lang = (bool) $use_directory_for_default_lang;
$this->urls_settings = $urls_settings;
$this->language_codes_map = array_combine( $active_languages, $active_languages );
$this->language_codes_map = apply_filters( 'wpml_language_codes_map', $this->language_codes_map );
$this->language_codes_reverse_map = array_flip( $this->language_codes_map );
}
public function add_hooks() {
add_filter( 'rest_url', [ $this, 'convertRestUrl' ] );
}
public function remove_hooks() {
remove_filter( 'rest_url', [ $this, 'convertRestUrl' ] );
}
/**
* @param string $url
*
* @return string
*/
public function convertRestUrl( $url ) {
/** @var SitePress */
global $sitepress;
$matchTrailingSlash = $url[ strlen( $url ) - 1 ] === '/' ? 'trailingslashit' : 'untrailingslashit';
return $matchTrailingSlash( $this->convert_url_string( $url, $sitepress->get_current_language() ) );
}
public function get_lang_from_url_string( $url ) {
$url_path = $this->get_url_path( wpml_strip_subdir_from_url( $url ) );
$lang = $this->extract_lang_from_url_path( $url_path );
if ( $lang && in_array( $lang, $this->active_languages, true ) ) {
return $lang;
}
return $this->use_directory_for_default_lang ? null : $this->default_language;
}
public function validate_language( $language, $url ) {
if ( ! ( null === $language && $this->use_directory_for_default_lang && ! $this->get_url_helper()->is_url_admin( $url ) ) ) {
$language = parent::validate_language( $language, $url );
}
return $language;
}
public function convert_url_string( $source_url, $code ) {
if ( $this->is_root_url( $source_url ) || $this->skip_convert_url_string( $source_url, $code ) ) {
return $source_url;
}
$source_url = $this->filter_source_url( $source_url );
$absolute_home_url = trailingslashit( preg_replace( '#^(http|https)://#', '', $this->get_url_helper()->get_abs_home() ) );
$absolute_home_url = strpos( $source_url, $absolute_home_url ) === false ? trailingslashit( get_option( 'home' ) ) : $absolute_home_url;
$current_language = $this->get_lang_from_url_string( $source_url );
$code = $this->get_language_of_current_dir( $code, '' );
$current_language = $this->get_language_of_current_dir( $current_language, '' );
$code = isset( $this->language_codes_map[ $code ] ) ? $this->language_codes_map[ $code ] : $code;
$current_language = isset( $this->language_codes_map[ $current_language ] ) ? $this->language_codes_map[ $current_language ] : $current_language;
$source_url = str_replace(
[
trailingslashit( $absolute_home_url . $current_language ),
'/' . $code . '//',
],
[
$code ? ( $absolute_home_url . $code . '/' ) : trailingslashit( $absolute_home_url ),
'/' . $code . '/',
],
$source_url
);
return $this->slash_helper->maybe_user_trailingslashit( $source_url );
}
public function convert_admin_url_string( $source_url, $lang ) {
return $source_url; // Admin strings should not be converted with language in directories
}
/**
* @param string $url
* @param string $language
*
* @return string
*/
public function get_home_url_relative( $url, $language ) {
$language = $this->get_language_of_current_dir( $language, '' );
$language = isset( $this->language_codes_map[ $language ] ) ? $this->language_codes_map[ $language ] : $language;
if ( $language ) {
$parts = parse_url( get_option( 'home' ) );
$path = isset( $parts['path'] ) ? $parts['path'] : '';
$url = preg_replace( '@^' . $path . '@', '', $url );
return rtrim( $path, '/' ) . '/' . $language . $url;
} else {
return $url;
}
}
public function use_wp_login_url_converter() {
return true;
}
/**
* Will return true if root URL or child of root URL
*
* @param string $url
*
* @return bool
*/
private function is_root_url( $url ) {
$result = false;
if ( isset( $this->urls_settings['root_page'], $this->urls_settings['show_on_root'] ) &&
'page' === $this->urls_settings['show_on_root'] &&
! empty( $this->urls_settings['directory_for_default_language'] )
) {
$root_url = $this->get_root_url();
if ( $root_url ) {
$result = strpos( trailingslashit( $url ), $root_url ) === 0;
}
}
return $result;
}
/**
* @return string|bool
*/
private function get_root_url() {
if ( null === $this->root_url ) {
$root_post = get_post( $this->urls_settings['root_page'] );
if ( $root_post ) {
$this->root_url = trailingslashit( $this->get_url_helper()->get_abs_home() ) . $root_post->post_name;
$this->root_url = trailingslashit( $this->root_url );
} else {
$this->root_url = false;
}
}
return $this->root_url;
}
/**
* @param string $source_url
*
* @return string
*/
private function filter_source_url( $source_url ) {
if ( false === strpos( $source_url, '?' ) ) {
$source_url = trailingslashit( $source_url );
} elseif ( false !== strpos( $source_url, '?' ) && false === strpos( $source_url, '/?' ) ) {
$source_url = str_replace( '?', '/?', $source_url );
}
return $source_url;
}
/**
* @param string $url
*
* @return string
*/
private function get_url_path( $url ) {
if ( strpos( $url, 'http://' ) === 0 || strpos( $url, 'https://' ) === 0 ) {
$url_path = wpml_parse_url( $url, PHP_URL_PATH );
} else {
$pathparts = array_filter( explode( '/', $url ) );
if ( count( $pathparts ) > 1 ) {
unset( $pathparts[0] );
$url_path = implode( '/', $pathparts );
} else {
$url_path = $url;
}
}
return $url_path;
}
/**
* @param string $url_path
*
* @return string
*/
private function extract_lang_from_url_path( $url_path ) {
$fragments = ! empty( $url_path ) ? array_filter( explode( '/', $url_path ) ) : [''];
$lang = array_shift( $fragments );
$lang_get_parts = ! empty( $lang ) ? explode( '?', $lang ) : [''];
$lang = $lang_get_parts[0];
return isset( $this->language_codes_reverse_map[ $lang ] ) ? $this->language_codes_reverse_map[ $lang ] : $lang;
}
/**
* @param string $language_code
* @param null|string $value_if_default_language
*
* @return string|null
*/
private function get_language_of_current_dir( $language_code, $value_if_default_language = null ) {
if ( ! $this->use_directory_for_default_lang && $language_code === $this->default_language ) {
return $value_if_default_language;
}
return $language_code;
}
}

View File

@@ -0,0 +1,24 @@
<?php
interface IWPML_URL_Converter_Strategy {
public function add_hooks();
public function remove_hooks();
public function convert_url_string( $source_url, $lang );
public function convert_admin_url_string( $source_url, $lang );
public function validate_language( $language, $url );
public function get_lang_from_url_string( $url );
public function get_home_url_relative( $url, $lang );
public function fix_trailingslashit( $source_url );
public function skip_convert_url_string( $url, $lang_code );
public function use_wp_login_url_converter();
}