first commit
This commit is contained in:
@@ -0,0 +1,67 @@
|
||||
<?php
|
||||
|
||||
namespace WPML\UrlHandling;
|
||||
|
||||
use WPML\LIB\WP\Option;
|
||||
use function WPML\Container\make;
|
||||
|
||||
class WPLoginUrlConverterRules implements \IWPML_Action {
|
||||
|
||||
const MARKED_FOR_UPDATE_AND_VALIDATE_OR_ROLLBACK = 3;
|
||||
const MARKED_FOR_UPDATE = true;
|
||||
const UNMARKED = false;
|
||||
|
||||
const UPDATE_RULES_KEY = 'wpml_login_page_translation_update_rules';
|
||||
|
||||
public function add_hooks() {
|
||||
if ( Option::getOr( self::UPDATE_RULES_KEY, self::UNMARKED ) ) {
|
||||
add_filter( 'init', [ self::class, 'update' ] );
|
||||
}
|
||||
}
|
||||
|
||||
public static function markRulesForUpdating( $verify = false ) {
|
||||
Option::update(
|
||||
self::UPDATE_RULES_KEY,
|
||||
$verify ? self::MARKED_FOR_UPDATE_AND_VALIDATE_OR_ROLLBACK : self::MARKED_FOR_UPDATE
|
||||
);
|
||||
}
|
||||
|
||||
public static function update() {
|
||||
global $wp_rewrite;
|
||||
|
||||
if ( ! function_exists( 'save_mod_rewrite_rules' ) ) {
|
||||
require_once ABSPATH . 'wp-admin/includes/misc.php';
|
||||
}
|
||||
$wp_rewrite->rewrite_rules();
|
||||
save_mod_rewrite_rules();
|
||||
$wp_rewrite->flush_rules( false );
|
||||
|
||||
$needsValidation = self::MARKED_FOR_UPDATE_AND_VALIDATE_OR_ROLLBACK === (int) Option::get( self::UPDATE_RULES_KEY );
|
||||
Option::update( self::UPDATE_RULES_KEY, self::UNMARKED );
|
||||
|
||||
if ( $needsValidation ) {
|
||||
static::validateOrDisable();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates that the Translated Login URL is accessible.
|
||||
* Used to validate the setting when enabled by default.
|
||||
*/
|
||||
public static function validateOrDisable() {
|
||||
$translationLangs = \WPML\Setup\Option::getTranslationLangs();
|
||||
|
||||
if ( empty( $translationLangs ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
/** @var \WPML_URL_Converter $urlConverter */
|
||||
$urlConverter = make( \WPML_URL_Converter::class );
|
||||
$newUrl = $urlConverter->convert_url( wp_login_url(), $translationLangs[0] );
|
||||
|
||||
$loginResponseCode = wp_remote_retrieve_response_code( wp_remote_get( $newUrl ) );
|
||||
if ( 200 !== $loginResponseCode ) {
|
||||
WPLoginUrlConverter::disable();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
<?php
|
||||
|
||||
use WPML\FP\Str;
|
||||
use WPML\FP\Lst;
|
||||
use WPML\FP\Fns;
|
||||
use WPML\FP\Wrapper;
|
||||
use function WPML\FP\pipe;
|
||||
|
||||
class WPML_Absolute_Links_Blacklist {
|
||||
|
||||
private $blacklist_requests;
|
||||
|
||||
public function __construct( $blacklist_requests ) {
|
||||
$this->blacklist_requests = $blacklist_requests;
|
||||
if ( ! is_array( $this->blacklist_requests ) ) {
|
||||
$this->blacklist_requests = array();
|
||||
}
|
||||
}
|
||||
|
||||
public function is_blacklisted( $request ) {
|
||||
$isBlacklisted = function ( $request ) {
|
||||
return Lst::includes( $request, $this->blacklist_requests )
|
||||
|| $this->is_blacklisted_with_regex( $request );
|
||||
};
|
||||
|
||||
return Wrapper::of( $request )
|
||||
->map( Str::split( '/' ) )
|
||||
->map( Fns::map( Fns::unary( pipe( 'urlencode', 'strtolower' ) ) ) )
|
||||
->map( Lst::join( '/' ) )
|
||||
->map( $isBlacklisted )
|
||||
->get();
|
||||
}
|
||||
|
||||
private function is_blacklisted_with_regex( $request ) {
|
||||
foreach ( $this->blacklist_requests as $blacklist_request ) {
|
||||
if ( $this->is_regex( $blacklist_request ) && preg_match( $blacklist_request, $request ) ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private function is_regex( $blacklist_request ) {
|
||||
return strpos( $blacklist_request, '/' ) === 0 && strrpos( $blacklist_request, '/' ) === strlen( $blacklist_request ) - 1;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,146 @@
|
||||
<?php
|
||||
|
||||
use WPML\Utils\AutoAdjustIds;
|
||||
|
||||
class WPML_Absolute_To_Permalinks {
|
||||
|
||||
private $taxonomies_query;
|
||||
private $lang;
|
||||
|
||||
/** @var SitePress $sitepress */
|
||||
private $sitepress;
|
||||
|
||||
/** @var AutoAdjustIds $auto_adjust_ids */
|
||||
private $auto_adjust_ids;
|
||||
|
||||
public function __construct( SitePress $sitepress, AutoAdjustIds $auto_adjust_ids = null ) {
|
||||
$this->sitepress = $sitepress;
|
||||
$this->auto_adjust_ids = $auto_adjust_ids ?: new AutoAdjustIds( $sitepress );
|
||||
}
|
||||
|
||||
public function convert_text( $text ) {
|
||||
|
||||
$this->lang = $this->sitepress->get_current_language();
|
||||
|
||||
$active_langs_reg_ex = implode( '|', array_keys( $this->sitepress->get_active_languages() ) );
|
||||
|
||||
if ( ! $this->taxonomies_query ) {
|
||||
$this->taxonomies_query = new WPML_WP_Taxonomy_Query( $this->sitepress->get_wp_api() );
|
||||
}
|
||||
|
||||
$home = rtrim( $this->sitepress->get_wp_api()->get_option( 'home' ), '/' );
|
||||
$parts = parse_url( $home );
|
||||
$abshome = $parts['scheme'] . '://' . $parts['host'];
|
||||
$path = isset( $parts['path'] ) ? ltrim( $parts['path'], '/' ) : '';
|
||||
$tx_qvs = join( '|', $this->taxonomies_query->get_query_vars() );
|
||||
$reg_ex = '@<a([^>]+)?href="((' . $abshome . ')?/' . $path . '/?(' . $active_langs_reg_ex . ')?\?(p|page_id|cat_ID|' . $tx_qvs . ')=([0-9a-z-]+))(#?[^"]*)"([^>]+)?>@i';
|
||||
$text = preg_replace_callback( $reg_ex, [ $this, 'show_permalinks_cb' ], $text );
|
||||
|
||||
return $text;
|
||||
}
|
||||
|
||||
function show_permalinks_cb( $matches ) {
|
||||
|
||||
$parts = $this->get_found_parts( $matches );
|
||||
|
||||
$url = $this->auto_adjust_ids->runWith(
|
||||
function() use ( $parts ) {
|
||||
return $this->get_url( $parts );
|
||||
}
|
||||
);
|
||||
|
||||
if ( $this->sitepress->get_wp_api()->is_wp_error( $url ) || empty( $url ) ) {
|
||||
return $parts->whole;
|
||||
}
|
||||
|
||||
$fragment = $this->get_fragment( $url, $parts );
|
||||
|
||||
if ( 'widget_text' == $this->sitepress->get_wp_api()->current_filter() ) {
|
||||
$url = $this->sitepress->convert_url( $url );
|
||||
}
|
||||
|
||||
return '<a' . $parts->pre_href . 'href="' . $url . $fragment . '"' . $parts->trail . '>';
|
||||
}
|
||||
|
||||
private function get_found_parts( $matches ) {
|
||||
return (object) array(
|
||||
'whole' => $matches[0],
|
||||
'pre_href' => $matches[1],
|
||||
'content_type' => $matches[5],
|
||||
'id' => $matches[6],
|
||||
'fragment' => $matches[7],
|
||||
'trail' => isset( $matches[8] ) ? $matches[8] : '',
|
||||
);
|
||||
}
|
||||
|
||||
private function get_url( $parts ) {
|
||||
$tax = $this->taxonomies_query->find( $parts->content_type );
|
||||
|
||||
if ( $parts->content_type == 'cat_ID' ) {
|
||||
$url = $this->sitepress->get_wp_api()->get_category_link( $parts->id );
|
||||
} elseif ( $tax ) {
|
||||
$url = $this->sitepress->get_wp_api()->get_term_link( $parts->id, $tax );
|
||||
} else {
|
||||
$url = $this->sitepress->get_wp_api()->get_permalink( $parts->id );
|
||||
}
|
||||
|
||||
return $url;
|
||||
}
|
||||
|
||||
private function get_fragment( $url, $parts ) {
|
||||
$fragment = $parts->fragment;
|
||||
$fragment = $this->remove_query_in_wrong_lang( $fragment );
|
||||
if ( $fragment != '' ) {
|
||||
$fragment = str_replace( '&', '&', $fragment );
|
||||
$fragment = str_replace( '&', '&', $fragment );
|
||||
if ( $fragment[0] == '&' ) {
|
||||
if ( strpos( $fragment, '?' ) === false && strpos( $url, '?' ) === false ) {
|
||||
$fragment[0] = '?';
|
||||
}
|
||||
}
|
||||
|
||||
if ( strpos( $url, '?' ) ) {
|
||||
$fragment = $this->check_for_duplicate_lang_query( $fragment, $url );
|
||||
}
|
||||
}
|
||||
|
||||
return $fragment;
|
||||
}
|
||||
|
||||
private function remove_query_in_wrong_lang( $fragment ) {
|
||||
if ( $fragment != '' ) {
|
||||
$fragment = str_replace( '&', '&', $fragment );
|
||||
$fragment = str_replace( '&', '&', $fragment );
|
||||
$start = $fragment[0];
|
||||
parse_str( substr( $fragment, 1 ), $fragment_query );
|
||||
if ( isset( $fragment_query['lang'] ) ) {
|
||||
if ( $fragment_query['lang'] != $this->lang ) {
|
||||
unset( $fragment_query['lang'] );
|
||||
|
||||
$fragment = build_query( $fragment_query );
|
||||
if ( strlen( $fragment ) ) {
|
||||
$fragment = $start . $fragment;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return $fragment;
|
||||
}
|
||||
|
||||
private function check_for_duplicate_lang_query( $fragment, $url ) {
|
||||
$url_parts = explode( '?', $url );
|
||||
parse_str( $url_parts[1], $url_query );
|
||||
|
||||
if ( isset( $url_query['lang'] ) ) {
|
||||
parse_str( substr( $fragment, 1 ), $fragment_query );
|
||||
if ( isset( $fragment_query['lang'] ) ) {
|
||||
unset( $fragment_query['lang'] );
|
||||
$fragment = build_query( $fragment_query );
|
||||
if ( strlen( $fragment ) ) {
|
||||
$fragment = '&' . $fragment;
|
||||
}
|
||||
}
|
||||
}
|
||||
return $fragment;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
class WPML_Allowed_Redirect_Hosts extends WPML_SP_User {
|
||||
|
||||
public function __construct( &$sitepress ) {
|
||||
parent::__construct( $sitepress );
|
||||
}
|
||||
|
||||
public function get_hosts( $hosts ) {
|
||||
$domains = $this->sitepress->get_setting( 'language_domains' );
|
||||
$default_language = $this->sitepress->get_default_language();
|
||||
$default_home = $this->sitepress->convert_url( $this->sitepress->get_wp_api()->get_home_url(), $default_language );
|
||||
$home_schema = wpml_parse_url( $default_home, PHP_URL_SCHEME ) . '://';
|
||||
|
||||
if ( ! isset( $domains[ $default_language ] ) ) {
|
||||
$domains[ $default_language ] = wpml_parse_url( $default_home, PHP_URL_HOST );
|
||||
}
|
||||
|
||||
$active_languages = $this->sitepress->get_active_languages();
|
||||
|
||||
foreach ( $domains as $code => $url ) {
|
||||
if ( ! empty( $active_languages[ $code ] ) ) {
|
||||
$url = $home_schema . $url;
|
||||
$parts = wpml_parse_url( $url );
|
||||
if ( isset( $parts['host'] ) && ! in_array( $parts['host'], $hosts ) ) {
|
||||
$hosts[] = $parts['host'];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $hosts;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
class WPML_Endpoints_Support_Factory implements IWPML_Frontend_Action_Loader, IWPML_Backend_Action_Loader, IWPML_Deferred_Action_Loader {
|
||||
|
||||
public function get_load_action() {
|
||||
return 'plugins_loaded';
|
||||
}
|
||||
|
||||
/**
|
||||
* @return WPML_Endpoints_Support
|
||||
*/
|
||||
public function create() {
|
||||
global $sitepress, $wpml_post_translations;
|
||||
|
||||
if ( $this->are_st_functions_loaded() ) {
|
||||
return new WPML_Endpoints_Support( $wpml_post_translations, $sitepress->get_current_language(), $sitepress->get_default_language() );
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
private function are_st_functions_loaded() {
|
||||
return function_exists( 'icl_get_string_id' );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,281 @@
|
||||
<?php
|
||||
|
||||
class WPML_Endpoints_Support {
|
||||
|
||||
const REGISTERED_ENDPOINTS_OPTION_KEY = 'wpml_registered_endpoints';
|
||||
const STRING_CONTEXT = 'WP Endpoints';
|
||||
|
||||
/**
|
||||
* @var WPML_Post_Translation
|
||||
*/
|
||||
private $post_translations;
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $current_language;
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $default_language;
|
||||
|
||||
public function __construct( WPML_Post_Translation $post_translations, $current_language, $default_language ) {
|
||||
$this->post_translations = $post_translations;
|
||||
$this->current_language = $current_language;
|
||||
$this->default_language = $default_language;
|
||||
}
|
||||
|
||||
public function add_hooks() {
|
||||
add_action( 'init', array( $this, 'add_endpoints_translations' ) );
|
||||
add_action( 'generate_rewrite_rules', array( $this, 'register_rewrite_rules_strings' ) );
|
||||
|
||||
add_filter( 'option_rewrite_rules', array(
|
||||
$this,
|
||||
'translate_endpoints_in_rewrite_rules'
|
||||
), 0, 1 ); // high priority
|
||||
add_filter( 'page_link', array( $this, 'endpoint_permalink_filter' ), 10, 2 );
|
||||
add_filter( 'wpml_ls_language_url', array( $this, 'add_endpoint_to_current_ls_language_url' ), 10, 2 );
|
||||
add_filter( 'wpml_get_endpoint_translation', array( $this, 'get_endpoint_translation' ), 10, 3 );
|
||||
add_filter( 'wpml_register_endpoint_string', array( $this, 'register_endpoint_string' ), 10, 2 );
|
||||
add_filter( 'wpml_get_endpoint_url', array( $this, 'get_endpoint_url' ), 10, 4 );
|
||||
add_filter( 'wpml_get_current_endpoint', array( $this, 'get_current_endpoint' ) );
|
||||
add_filter( 'wpml_get_registered_endpoints', array( $this, 'get_registered_endpoints' ) );
|
||||
}
|
||||
|
||||
public function add_endpoints_translations() {
|
||||
|
||||
if ( $this->default_language !== $this->current_language ) {
|
||||
|
||||
$registered_endpoints = $this->get_registered_endpoints();
|
||||
|
||||
if ( $registered_endpoints ) {
|
||||
|
||||
foreach ( $registered_endpoints as $endpoint_key => $endpoint_value ) {
|
||||
|
||||
$endpoint_translation = $this->get_endpoint_translation( $endpoint_key, $endpoint_value );
|
||||
|
||||
if ( $endpoint_value !== urldecode( $endpoint_translation ) ) {
|
||||
add_rewrite_endpoint( $endpoint_translation, EP_ROOT | EP_PAGES );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
do_action( 'wpml_after_add_endpoints_translations', $this->current_language );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param WP_Rewrite $wp_rewrite
|
||||
*/
|
||||
public function register_rewrite_rules_strings( $wp_rewrite ) {
|
||||
|
||||
$registered_endpoints = array();
|
||||
|
||||
foreach ( $wp_rewrite->endpoints as $endpoint ) {
|
||||
$this->register_endpoint_string( $endpoint[1], $endpoint[2] );
|
||||
$registered_endpoints[ $endpoint[1] ] = $endpoint[2];
|
||||
}
|
||||
|
||||
update_option( self::REGISTERED_ENDPOINTS_OPTION_KEY, $registered_endpoints );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $key
|
||||
* @param string $endpoint
|
||||
* @param null|string $language
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_endpoint_translation( $key, $endpoint, $language = null ) {
|
||||
|
||||
$this->register_endpoint_string( $key, $endpoint );
|
||||
|
||||
$endpoint_translation = apply_filters( 'wpml_translate_single_string', $endpoint, self::STRING_CONTEXT, $key, $language ? $language : $this->current_language );
|
||||
|
||||
if ( ! empty( $endpoint_translation ) ) {
|
||||
return implode( '/', array_map( 'rawurlencode', explode( '/', $endpoint_translation ) ) );
|
||||
} else {
|
||||
return $endpoint;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $key
|
||||
* @param string $endpoint
|
||||
*/
|
||||
public function register_endpoint_string( $key, $endpoint ) {
|
||||
|
||||
$string = icl_get_string_id( $endpoint, self::STRING_CONTEXT, $key );
|
||||
|
||||
if ( ! $string ) {
|
||||
icl_register_string( self::STRING_CONTEXT, $key, $endpoint );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $value
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function translate_endpoints_in_rewrite_rules( $value ) {
|
||||
|
||||
if ( ! empty( $value ) ) {
|
||||
|
||||
$registered_endpoints = $this->get_registered_endpoints();
|
||||
|
||||
if ( $registered_endpoints ) {
|
||||
|
||||
foreach ( $registered_endpoints as $endpoint_key => $endpoint_value ) {
|
||||
|
||||
$endpoint_translation = $this->get_endpoint_translation( $endpoint_key, $endpoint_value );
|
||||
|
||||
if ( $endpoint_value === urldecode( $endpoint_translation ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$buff_value = array();
|
||||
|
||||
foreach ( $value as $k => $v ) {
|
||||
$k = preg_replace( '/(\/|^)' . $endpoint_value . '(\/)?(\(\/\(\.\*\)\)\?\/\?\$)/', '$1' . $endpoint_translation . '$2$3', $k );
|
||||
$buff_value[ $k ] = $v;
|
||||
}
|
||||
$value = $buff_value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $link
|
||||
* @param int $pid
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function endpoint_permalink_filter( $link, $pid ) {
|
||||
global $post, $wp;
|
||||
|
||||
if ( isset( $post->ID ) && $post->ID && ! is_admin() ) {
|
||||
|
||||
$page_lang = $this->post_translations->get_element_lang_code( $post->ID );
|
||||
|
||||
if ( ! $page_lang ) {
|
||||
return $link;
|
||||
}
|
||||
|
||||
if ( $pid === $post->ID ) {
|
||||
$pid_in_page_lang = $pid;
|
||||
} else {
|
||||
$translations = $this->post_translations->get_element_translations( $pid );
|
||||
$pid_in_page_lang = isset( $translations[ $page_lang ] ) ? $translations[ $page_lang ] : $pid;
|
||||
}
|
||||
|
||||
$current_lang = apply_filters( 'wpml_current_language', $this->current_language );
|
||||
|
||||
if (
|
||||
(
|
||||
$current_lang != $page_lang &&
|
||||
$pid_in_page_lang == $post->ID
|
||||
) ||
|
||||
apply_filters( 'wpml_endpoint_force_permalink_filter', false, $current_lang, $page_lang )
|
||||
) {
|
||||
|
||||
$endpoints = $this->get_registered_endpoints();
|
||||
|
||||
foreach ( $endpoints as $key => $endpoint ) {
|
||||
if ( isset( $wp->query_vars[ $key ] ) ) {
|
||||
|
||||
list( $link, $endpoint ) = apply_filters( 'wpml_endpoint_permalink_filter', array( $link, $endpoint ), $key );
|
||||
|
||||
$link = $this->get_endpoint_url( $this->get_endpoint_translation( $key, $endpoint, $current_lang ), $wp->query_vars[ $key ], $link, $page_lang );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $link;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $endpoint
|
||||
* @param string $value
|
||||
* @param string $permalink
|
||||
* @param bool|string $page_lang
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_endpoint_url( $endpoint, $value = '', $permalink = '', $page_lang = false ) {
|
||||
|
||||
$value = apply_filters( 'wpml_endpoint_url_value', $value, $page_lang );
|
||||
|
||||
if ( get_option( 'permalink_structure' ) ) {
|
||||
|
||||
$query_string = '';
|
||||
if ( strstr( $permalink, '?' ) ) {
|
||||
$query_string = '?' . parse_url( $permalink, PHP_URL_QUERY );
|
||||
$permalink = current( explode( '?', $permalink ) );
|
||||
}
|
||||
$url = trailingslashit( $permalink ) . $endpoint . '/' . $value . $query_string;
|
||||
} else {
|
||||
$url = add_query_arg( $endpoint, $value, $permalink );
|
||||
}
|
||||
|
||||
return $url;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $url
|
||||
* @param array $data
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function add_endpoint_to_current_ls_language_url( $url, $data ) {
|
||||
global $post;
|
||||
|
||||
$post_lang = '';
|
||||
$current_endpoint = array();
|
||||
|
||||
if ( isset( $post->ID ) && $post->ID ) {
|
||||
|
||||
$post_lang = $this->post_translations->get_element_lang_code( $post->ID );
|
||||
$current_endpoint = $this->get_current_endpoint( $data['code'] );
|
||||
|
||||
if ( $post_lang === $data['code'] && $current_endpoint ) {
|
||||
$url = $this->get_endpoint_url( $current_endpoint['key'], $current_endpoint['value'], $url );
|
||||
}
|
||||
}
|
||||
|
||||
return apply_filters( 'wpml_current_ls_language_url_endpoint', $url, $post_lang, $data, $current_endpoint );
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function get_registered_endpoints() {
|
||||
|
||||
return get_option( self::REGISTERED_ENDPOINTS_OPTION_KEY, array() );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $language
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function get_current_endpoint( $language ) {
|
||||
global $wp;
|
||||
|
||||
$current_endpoint = array();
|
||||
|
||||
foreach ( $this->get_registered_endpoints() as $key => $value ) {
|
||||
if ( isset( $wp->query_vars[ $key ] ) ) {
|
||||
$current_endpoint['key'] = $this->get_endpoint_translation( $key, $value, $language );
|
||||
$current_endpoint['value'] = $wp->query_vars[ $key ];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return $current_endpoint;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
<?php
|
||||
|
||||
class WPML_Home_Url_Filter_Context {
|
||||
|
||||
const REST_REQUEST = 'rest-request';
|
||||
const REWRITE_RULES = 'rewrite-rules';
|
||||
const PAGINATION = 'pagination';
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
private $language_negotiation_type;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $orig_scheme;
|
||||
|
||||
/**
|
||||
* @var WPML_Debug_BackTrace
|
||||
*/
|
||||
private $debug_backtrace;
|
||||
|
||||
public function __construct( $language_negotiation_type, $orig_scheme, WPML_Debug_BackTrace $debug_backtrace ) {
|
||||
$this->language_negotiation_type = $language_negotiation_type;
|
||||
$this->orig_scheme = $orig_scheme;
|
||||
$this->debug_backtrace = $debug_backtrace;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function should_not_filter() {
|
||||
return $this->is_rest_request()
|
||||
|| $this->rewriting_rules()
|
||||
|| $this->pagination_link();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
private function is_rest_request() {
|
||||
return in_array( $this->orig_scheme, array( 'json', 'rest' ), true );
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
private function rewriting_rules() {
|
||||
return $this->debug_backtrace->is_class_function_in_call_stack( 'WP_Rewrite', 'rewrite_rules' );
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
private function pagination_link() {
|
||||
return WPML_LANGUAGE_NEGOTIATION_TYPE_PARAMETER === $this->language_negotiation_type
|
||||
&& $this->debug_backtrace->is_function_in_call_stack( 'get_pagenum_link' );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
<?php
|
||||
|
||||
class WPML_Include_Url extends WPML_WPDB_User {
|
||||
|
||||
private $unfiltered_home_url;
|
||||
private $requested_host;
|
||||
|
||||
public function __construct( &$wpdb, $requested_host ) {
|
||||
parent::__construct( $wpdb );
|
||||
add_filter( 'style_loader_src', array( $this, 'filter_include_url' ) );
|
||||
add_filter( 'script_loader_src', array( $this, 'filter_include_url' ) );
|
||||
add_filter( 'the_password_form', array( $this, 'wpml_password_form_filter' ) );
|
||||
$this->requested_host = $requested_host;
|
||||
}
|
||||
|
||||
public function filter_include_url( $result ) {
|
||||
$domains = wpml_get_setting_filter( array(), 'language_domains' );
|
||||
$domains = preg_replace( '#^(http(?:s?))://#', '', array_map( 'untrailingslashit', $domains ) );
|
||||
if ( (bool) $domains === true ) {
|
||||
$php_host_in_domain = wpml_parse_url( $result, PHP_URL_HOST );
|
||||
$domains[] = wpml_parse_url( $this->get_unfiltered_home(), PHP_URL_HOST );
|
||||
foreach ( $domains as $dom ) {
|
||||
if ( strpos( trailingslashit( $php_host_in_domain ), trailingslashit( $dom ) ) === 0 ) {
|
||||
$http_host_parts = explode( ':', $this->requested_host );
|
||||
unset( $http_host_parts[1] );
|
||||
$http_host_without_port = implode( $http_host_parts );
|
||||
$result = str_replace( $php_host_in_domain, $http_host_without_port, $result );
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function wpml_password_form_filter( $form ) {
|
||||
if ( preg_match( '/action="(.*?)"/', $form, $matches ) ) {
|
||||
$new_url = $this->filter_include_url( $matches[1] );
|
||||
$form_action = str_replace( $matches[1], $new_url, $matches[0] );
|
||||
$form = str_replace( $matches[0], $form_action, $form );
|
||||
}
|
||||
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value of the unfiltered home option directly from the wp_options table.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_unfiltered_home() {
|
||||
$this->unfiltered_home_url = $this->unfiltered_home_url
|
||||
? $this->unfiltered_home_url
|
||||
: $this->wpdb->get_var(
|
||||
" SELECT option_value
|
||||
FROM {$this->wpdb->options}
|
||||
WHERE option_name = 'home'
|
||||
LIMIT 1"
|
||||
);
|
||||
|
||||
return $this->unfiltered_home_url;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
class WPML_Language_Domains {
|
||||
|
||||
private $domains;
|
||||
|
||||
public function __construct(
|
||||
SitePress $sitepress,
|
||||
WPML_URL_Converter_Url_Helper $converter_url_helper
|
||||
) {
|
||||
$this->domains = $sitepress->get_setting( 'language_domains' );
|
||||
|
||||
$this->domains[ $sitepress->get_default_language() ] = wpml_parse_url( $converter_url_helper->get_abs_home(), PHP_URL_HOST );
|
||||
}
|
||||
|
||||
public function get( $lang ) {
|
||||
return $this->domains[ $lang ];
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,298 @@
|
||||
<?php
|
||||
|
||||
class WPML_Root_Page {
|
||||
|
||||
public static function init() {
|
||||
if ( self::uses_html_root()
|
||||
|| self::get_root_id() > 0
|
||||
|| strpos( (string) filter_var( $_SERVER['REQUEST_URI'] ), 'wpml_root_page=1' ) !== false
|
||||
|| (bool) filter_input( INPUT_POST, '_wpml_root_page' ) === true
|
||||
) {
|
||||
global $wpml_root_page_actions;
|
||||
|
||||
$wpml_root_page_actions = wpml_get_root_page_actions_obj();
|
||||
add_action( 'init', array( $wpml_root_page_actions, 'wpml_home_url_init' ), 0 );
|
||||
add_filter( 'wp_page_menu_args', array( $wpml_root_page_actions, 'wpml_home_url_exclude_root_page_from_menus' ) );
|
||||
add_filter( 'wp_get_nav_menu_items', array( $wpml_root_page_actions, 'exclude_root_page_menu_item' ), 10, 1 );
|
||||
add_filter( 'wp_list_pages_excludes', array( $wpml_root_page_actions, 'wpml_home_url_exclude_root_page' ) );
|
||||
add_filter( 'page_attributes_dropdown_pages_args', array( $wpml_root_page_actions, 'wpml_home_url_exclude_root_page2' ) );
|
||||
add_filter( 'get_pages', array( $wpml_root_page_actions, 'wpml_home_url_get_pages' ) );
|
||||
add_action( 'save_post', array( $wpml_root_page_actions, 'wpml_home_url_save_post_actions' ), 0, 2 );
|
||||
|
||||
if ( self::get_root_id() > 0 ) {
|
||||
add_filter( 'template_include', array( 'WPML_Root_Page', 'wpml_home_url_template_include' ) );
|
||||
add_filter( 'the_preview', array( 'WPML_Root_Page', 'front_page_id_filter' ) );
|
||||
}
|
||||
$root_page_actions = wpml_get_root_page_actions_obj();
|
||||
add_action( 'icl_set_element_language', array( $root_page_actions, 'delete_root_page_lang' ), 10, 0 );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the value in $_SERVER['REQUEST_URI] points towards the root page.
|
||||
* Therefore this can be used to check if the current request points towards the root page.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function is_current_request_root() {
|
||||
return self::is_root_page( $_SERVER['REQUEST_URI'] );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $requested_url
|
||||
* Checks if a requested url points towards the root page.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function is_root_page( $requested_url ) {
|
||||
$cached_val = wp_cache_get( md5( $requested_url ) );
|
||||
|
||||
if ( $cached_val !== false ) {
|
||||
return (bool) $cached_val;
|
||||
}
|
||||
|
||||
$request_parts = self::get_slugs_and_get_query( $requested_url );
|
||||
$slugs = $request_parts['slugs'];
|
||||
$gets = $request_parts['querystring'];
|
||||
|
||||
$target_of_gets = self::get_query_target_from_query_string( $gets );
|
||||
|
||||
if ( $target_of_gets == WPML_QUERY_IS_ROOT ) {
|
||||
$result = true;
|
||||
} elseif ( $target_of_gets == WPML_QUERY_IS_OTHER_THAN_ROOT || $target_of_gets == WPML_QUERY_IS_NOT_FOR_POST && self::query_points_to_archive( $gets ) ) {
|
||||
$result = false;
|
||||
} else {
|
||||
$result = self::slugs_point_to_root( $slugs );
|
||||
}
|
||||
|
||||
wp_cache_add( md5( $requested_url ), ( $result === true ? 1 : 0 ) );
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
public static function uses_html_root() {
|
||||
$urls = icl_get_setting( 'urls' );
|
||||
|
||||
return isset( $urls['root_page'] ) && isset( $urls['show_on_root'] ) && $urls['directory_for_default_language'] && 'html_file' === $urls['show_on_root'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the id of the root page or false if it isn't set.
|
||||
*
|
||||
* @return bool|int
|
||||
*/
|
||||
public static function get_root_id() {
|
||||
$root_actions = wpml_get_root_page_actions_obj();
|
||||
|
||||
return $root_actions->get_root_page_id();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the slug of the root page or false if non exists.
|
||||
*
|
||||
* @return bool|string
|
||||
*/
|
||||
private static function get_root_slug() {
|
||||
|
||||
$root_id = self::get_root_id();
|
||||
|
||||
$root_slug = false;
|
||||
if ( $root_id ) {
|
||||
$root_page_object = get_post( $root_id );
|
||||
if ( $root_page_object && isset( $root_page_object->post_name ) ) {
|
||||
$root_slug = $root_page_object->post_name;
|
||||
}
|
||||
}
|
||||
|
||||
return $root_slug;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $requested_url
|
||||
* Takes a request_url in the format of $_SERVER['REQUEST_URI']
|
||||
* and returns an associative array containing its slugs ans query string.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private static function get_slugs_and_get_query( $requested_url ) {
|
||||
$result = array();
|
||||
$request_path = wpml_parse_url( $requested_url, PHP_URL_PATH );
|
||||
$request_path = wpml_strip_subdir_from_url( $request_path );
|
||||
$slugs = self::get_slugs_array( $request_path );
|
||||
$result['slugs'] = $slugs;
|
||||
|
||||
$query_string = wpml_parse_url( $requested_url, PHP_URL_QUERY );
|
||||
$result['querystring'] = ! $query_string ? '' : $query_string;
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $path
|
||||
* Turns a query string into an array of its slugs.
|
||||
* The array is filtered so to not contain empty values and
|
||||
* consecutively and numerically indexed starting at 0.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private static function get_slugs_array( $path ) {
|
||||
$slugs = explode( '/', $path );
|
||||
$slugs = array_filter( $slugs );
|
||||
$slugs = array_values( $slugs );
|
||||
|
||||
return $slugs;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $slugs
|
||||
* Checks if a given set of slugs points towards the root page or not.
|
||||
* The result of this can always be overridden by GET parameters and is not a certain
|
||||
* check as to being on the root page or not.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private static function slugs_point_to_root( $slugs ) {
|
||||
$result = true;
|
||||
if ( ! empty( $slugs ) ) {
|
||||
$root_slug = self::get_root_slug();
|
||||
|
||||
$last_slug = array_pop( $slugs );
|
||||
$second_slug = array_pop( $slugs );
|
||||
$third_slug = array_pop( $slugs );
|
||||
|
||||
if ( ( $root_slug != $last_slug && ! is_numeric( $last_slug ) )
|
||||
|| ( is_numeric( $last_slug )
|
||||
&& $second_slug != null
|
||||
&& $root_slug !== $second_slug
|
||||
&& ( ( 'page' !== $second_slug )
|
||||
|| ( 'page' === $second_slug && ( $third_slug && $third_slug != $root_slug ) ) ) )
|
||||
) {
|
||||
$result = false;
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Turns a given query string into an associative array of its parameters.
|
||||
*
|
||||
* @param string $query_string
|
||||
* @return array<string,string>
|
||||
*/
|
||||
private static function get_query_array_from_string( $query_string ) {
|
||||
$all_query_params = array();
|
||||
parse_str( $query_string, $all_query_params );
|
||||
|
||||
return $all_query_params;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $query_string
|
||||
* Checks if the WP_Query functionality can decisively recognize if a querystring points
|
||||
* towards an archive.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private static function query_points_to_archive( $query_string ) {
|
||||
|
||||
$root_page_actions = wpml_get_root_page_actions_obj();
|
||||
remove_action( 'parse_query', array( $root_page_actions, 'wpml_home_url_parse_query' ) );
|
||||
$query_string = str_replace( '?', '', $query_string );
|
||||
|
||||
$query = new WP_Query( $query_string );
|
||||
$is_archive = $query->is_archive();
|
||||
add_action( 'parse_query', array( $root_page_actions, 'wpml_home_url_parse_query' ) );
|
||||
|
||||
return $is_archive;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $query_string
|
||||
* Checks if a given query string decisively points towards or away from the root page.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
private static function get_query_target_from_query_string( $query_string ) {
|
||||
$params_array = self::get_query_array_from_string( $query_string );
|
||||
|
||||
return self::get_query_target_from_params_array( $params_array );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $query_params
|
||||
* Checks if a set of query parameters decisively points towards or away from the root page.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
private static function get_query_target_from_params_array( $query_params ) {
|
||||
|
||||
if ( ! isset( $query_params['p'] )
|
||||
&& ! isset( $query_params['page_id'] )
|
||||
&& ! isset( $query_params['name'] )
|
||||
&& ! isset( $query_params['pagename'] )
|
||||
&& ! isset( $query_params['page_name'] )
|
||||
&& ! isset( $query_params['attachment_id'] )
|
||||
) {
|
||||
$result = WPML_QUERY_IS_NOT_FOR_POST;
|
||||
} else {
|
||||
|
||||
$root_id = self::get_root_id();
|
||||
$root_slug = self::get_root_slug();
|
||||
|
||||
if ( ( isset( $query_params['p'] ) && $query_params['p'] != $root_id )
|
||||
|| ( isset( $query_params['page_id'] ) && $query_params['page_id'] != $root_id )
|
||||
|| ( isset( $query_params['name'] ) && $query_params['name'] != $root_slug )
|
||||
|| ( isset( $query_params['pagename'] ) && $query_params['pagename'] != $root_slug )
|
||||
|| ( isset( $query_params['preview_id'] ) && $query_params['preview_id'] != $root_id )
|
||||
|| ( isset( $query_params['attachment_id'] ) && $query_params['attachment_id'] != $root_id )
|
||||
) {
|
||||
$result = WPML_QUERY_IS_OTHER_THAN_ROOT;
|
||||
} else {
|
||||
$result = WPML_QUERY_IS_ROOT;
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param false|WP_Post $post
|
||||
* Filters the postID used by the preview for the case of the root page preview.
|
||||
*
|
||||
* @return null|WP_Post
|
||||
*/
|
||||
public static function front_page_id_filter( $post ) {
|
||||
$preview_id = isset( $_GET['preview_id'] ) ? $_GET['preview_id'] : - 1;
|
||||
|
||||
if ( $preview_id == self::get_root_id() ) {
|
||||
$post = get_post( $preview_id );
|
||||
}
|
||||
|
||||
return $post;
|
||||
}
|
||||
|
||||
/**
|
||||
* Filters the template that is used for the root page
|
||||
*
|
||||
* @param string $template
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function wpml_home_url_template_include( $template ) {
|
||||
|
||||
return self::is_current_request_root() ? self::get_root_page_template() : $template;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public static function get_root_page_template() {
|
||||
$page_template = get_page_template();
|
||||
if ( $page_template ) {
|
||||
return $page_template;
|
||||
}
|
||||
$singular_template = get_singular_template();
|
||||
return $singular_template ?: get_index_template();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,139 @@
|
||||
<?php
|
||||
|
||||
class WPML_Score_Hierarchy {
|
||||
|
||||
private $data = array();
|
||||
private $slugs = array();
|
||||
|
||||
/**
|
||||
* WPML_Score_Hierarchy constructor.
|
||||
*
|
||||
* @param object[] $data_set
|
||||
* @param string[] $slugs
|
||||
*/
|
||||
public function __construct( $data_set, $slugs ) {
|
||||
$this->data = $data_set;
|
||||
$this->slugs = $slugs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Array of best matched post_ids. Better matches have a lower index!
|
||||
*
|
||||
* @return int[]
|
||||
*/
|
||||
public function get_possible_ids_ordered() {
|
||||
$pages_with_name = $this->data;
|
||||
$slugs = $this->slugs;
|
||||
$parent_slugs = array_slice( $slugs, 0, - 1 );
|
||||
|
||||
foreach ( $this->data as $key => $page ) {
|
||||
if ( $page->parent_name ) {
|
||||
$slug_pos = array_keys( $slugs, $page->post_name, true );
|
||||
$par_slug_pos = array_keys( $slugs, $page->parent_name, true );
|
||||
if ( (bool) $par_slug_pos !== false
|
||||
&& (bool) $slug_pos !== false
|
||||
) {
|
||||
$remove = true;
|
||||
foreach ( $slug_pos as $child_slug_pos ) {
|
||||
if ( in_array( $child_slug_pos - 1, $par_slug_pos ) ) {
|
||||
$remove = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ( $remove === true ) {
|
||||
unset( $pages_with_name[ $key ] );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
$related_ids = array();
|
||||
$matching_ids = array();
|
||||
foreach ( $pages_with_name as $key => $page ) {
|
||||
$correct_slug = end( $slugs );
|
||||
if ( $page->post_name === $correct_slug ) {
|
||||
if ( $this->is_exactly_matching_all_slugs_in_order( $page ) ) {
|
||||
$matching_ids[] = (int) $page->ID;
|
||||
} else {
|
||||
$related_ids[ $page->ID ] = $this->calculate_score( $parent_slugs, $pages_with_name, $page );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
arsort( $related_ids );
|
||||
$related_ids = array_keys( $related_ids );
|
||||
|
||||
return array(
|
||||
'matching_ids' => $matching_ids,
|
||||
'related_ids' => $related_ids,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get page object by its id.
|
||||
*
|
||||
* @param int $id
|
||||
*
|
||||
* @return false|object
|
||||
*/
|
||||
private function get_page_by_id( $id ) {
|
||||
foreach ( $this->data as $page ) {
|
||||
if ( (int) $page->ID === (int) $id ) {
|
||||
return $page;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string[] $parent_slugs
|
||||
* @param object[] $pages_with_name
|
||||
* @param object $page
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
private function calculate_score( $parent_slugs, $pages_with_name, $page ) {
|
||||
$parent_positions = array_keys( $parent_slugs, $page->parent_name, true );
|
||||
$new_score = (bool) $parent_positions === true ? max( $parent_positions ) + 1 : ( $page->post_parent ? - 1 : 0 );
|
||||
if ( $page->post_parent ) {
|
||||
foreach ( $pages_with_name as $parent ) {
|
||||
if ( $parent->ID == $page->post_parent ) {
|
||||
$new_score += $this->calculate_score( array_slice( $parent_slugs, 0, count( $parent_slugs ) - 1 ), $pages_with_name, $parent );
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $new_score;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param stdClass $page
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function is_exactly_matching_all_slugs_in_order( $page ) {
|
||||
return $this->slugs === $this->get_slugs_for_page( $page );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param stdClass $current_page
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function get_slugs_for_page( $current_page ) {
|
||||
$slugs = array();
|
||||
|
||||
while ( $current_page && $current_page->post_name ) {
|
||||
$slugs[] = $current_page->post_name;
|
||||
$parent_name = $current_page->parent_name;
|
||||
$current_page = $this->get_page_by_id( $current_page->post_parent );
|
||||
|
||||
if ( ! $current_page && $parent_name ) {
|
||||
$slugs[] = $parent_name;
|
||||
}
|
||||
}
|
||||
|
||||
return array_reverse( $slugs );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
<?php
|
||||
|
||||
class WPML_URL_HTTP_Referer_Factory {
|
||||
|
||||
/**
|
||||
* @return WPML_URL_HTTP_Referer
|
||||
*/
|
||||
public function create() {
|
||||
return new WPML_URL_HTTP_Referer( new WPML_Rest( new WP_Http() ) );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
<?php
|
||||
|
||||
class WPML_URL_HTTP_Referer {
|
||||
|
||||
private $rest;
|
||||
|
||||
public function __construct( WPML_Rest $rest ) {
|
||||
$this->rest = $rest;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $backup_url
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_url( $backup_url ) {
|
||||
if ( ! isset( $_SERVER['HTTP_REFERER'] ) ) {
|
||||
return $backup_url;
|
||||
}
|
||||
|
||||
if ( WPML_Ajax::is_admin_ajax_request_called_from_frontend( $backup_url )
|
||||
|| $this->is_rest_request_called_from_post_edit_page()
|
||||
) {
|
||||
return $_SERVER['HTTP_REFERER'];
|
||||
}
|
||||
|
||||
return $backup_url;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool|int
|
||||
*/
|
||||
public function get_trid() {
|
||||
$referer_data = $request_uri_data = array();
|
||||
|
||||
if ( array_key_exists( 'HTTP_REFERER', $_SERVER ) ) {
|
||||
$query = (string) wpml_parse_url( $_SERVER['HTTP_REFERER'], PHP_URL_QUERY );
|
||||
parse_str( $query, $referer_data );
|
||||
}
|
||||
|
||||
if ( array_key_exists( 'REQUEST_URI', $_SERVER ) ) {
|
||||
$request_uri = (string) wpml_parse_url( $_SERVER['REQUEST_URI'], PHP_URL_QUERY );
|
||||
parse_str( $request_uri, $request_uri_data );
|
||||
}
|
||||
|
||||
/**
|
||||
* trid from `HTTP_REFERER` should be return only if `REQUEST_URI` also has trid set.
|
||||
*
|
||||
* @link https://onthegosystems.myjetbrains.com/youtrack/issue/wpmltm-1351
|
||||
*
|
||||
* Or when it is a rest request called in the post edit page (Gutenberg)
|
||||
* @link https://onthegosystems.myjetbrains.com/youtrack/issue/wpmlcore-5265
|
||||
*/
|
||||
return array_key_exists( 'trid', $referer_data ) && array_key_exists( 'trid', $request_uri_data )
|
||||
|| ( array_key_exists( 'trid', $referer_data ) && $this->is_rest_request_called_from_post_edit_page() )
|
||||
? (int) $referer_data['trid']
|
||||
: false;
|
||||
}
|
||||
|
||||
/**
|
||||
* We need this in order to detect the language when adding
|
||||
* translation from inside of a Gutenberg page while
|
||||
* they don't provide a JS API which allows us to do it
|
||||
*
|
||||
* @link https://github.com/WordPress/gutenberg/issues/5958
|
||||
* @link https://onthegosystems.myjetbrains.com/youtrack/issue/wpmlcore-5265
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function is_rest_request_called_from_post_edit_page() {
|
||||
return $this->rest->is_rest_request() && self::is_post_edit_page();
|
||||
}
|
||||
|
||||
public static function is_post_edit_page() {
|
||||
return isset( $_SERVER['HTTP_REFERER'] )
|
||||
&& ( strpos( $_SERVER['HTTP_REFERER'], 'wp-admin/post.php' )
|
||||
|| strpos( $_SERVER['HTTP_REFERER'], 'wp-admin/post-new.php' )
|
||||
|| strpos( $_SERVER['HTTP_REFERER'], 'wp-admin/edit.php' ) );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
use WPML\API\Sanitize;
|
||||
|
||||
class WPML_WP_In_Subdir_URL_Filters_Factory implements IWPML_Frontend_Action_Loader, IWPML_Backend_Action_Loader {
|
||||
|
||||
public function create() {
|
||||
/**
|
||||
* @var WPML_URL_Converter $wpml_url_converter
|
||||
* @var SitePress $sitepress
|
||||
*/
|
||||
global $wpml_url_converter, $sitepress;
|
||||
|
||||
$lang_negotiation_type = $sitepress->get_setting( 'language_negotiation_type', false );
|
||||
|
||||
if ( WPML_LANGUAGE_NEGOTIATION_TYPE_DIRECTORY === (int) $lang_negotiation_type ) {
|
||||
$request_uri = Sanitize::stringProp( 'REQUEST_URI', $_SERVER );
|
||||
$uri_without_subdir = wpml_strip_subdir_from_url( $request_uri );
|
||||
|
||||
if ( trim( $request_uri, '/' ) !== trim( $uri_without_subdir, '/' ) ) {
|
||||
$backtrace = new WPML_Debug_BackTrace( null, 5 );
|
||||
return new WPML_WP_In_Subdir_URL_Filters( $backtrace, $sitepress, $wpml_url_converter, $uri_without_subdir );
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
<?php
|
||||
|
||||
class WPML_WP_In_Subdir_URL_Filters implements IWPML_Action {
|
||||
|
||||
/** @var WPML_Debug_BackTrace $backtrace */
|
||||
private $backtrace;
|
||||
|
||||
/** @var SitePress $sitepress */
|
||||
private $sitepress;
|
||||
|
||||
/** @var WPML_URL_Converter $url_converter */
|
||||
private $url_converter;
|
||||
|
||||
/** @var string $uri_without_subdir */
|
||||
private $uri_without_subdir;
|
||||
|
||||
/**
|
||||
* @param WPML_Debug_BackTrace $backtrace
|
||||
* @param SitePress $sitepress
|
||||
* @param WPML_URL_Converter $url_converter
|
||||
* @param string $uri_without_subdir
|
||||
*/
|
||||
public function __construct(
|
||||
WPML_Debug_BackTrace $backtrace,
|
||||
SitePress $sitepress,
|
||||
WPML_URL_Converter $url_converter,
|
||||
$uri_without_subdir
|
||||
) {
|
||||
$this->url_converter = $url_converter;
|
||||
$this->backtrace = $backtrace;
|
||||
$this->sitepress = $sitepress;
|
||||
$this->url_converter = $url_converter;
|
||||
$this->uri_without_subdir = $uri_without_subdir;
|
||||
}
|
||||
|
||||
public function add_hooks() {
|
||||
add_filter( 'home_url', array( $this, 'home_url_filter_on_parse_request' ), PHP_INT_MAX );
|
||||
}
|
||||
|
||||
/**
|
||||
* This filter is only applied in `WP::parse_request` in order to get
|
||||
* the proper URI cleanup base in `$home_path_regex`
|
||||
*
|
||||
* @param string $home_url
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function home_url_filter_on_parse_request( $home_url ) {
|
||||
|
||||
if ( $this->backtrace->is_class_function_in_call_stack( 'WP', 'parse_request' ) ) {
|
||||
|
||||
if ( $this->request_uri_begins_with_lang() ) {
|
||||
/**
|
||||
* The URL is already filtered with the lang directory.
|
||||
* e.g. http://example.org/subdir/en/
|
||||
*/
|
||||
return $home_url;
|
||||
}
|
||||
|
||||
/**
|
||||
* We return the root URL of the WP install.
|
||||
* e.g. http://example.org/subdir/
|
||||
*/
|
||||
return $this->url_converter->get_abs_home();
|
||||
}
|
||||
|
||||
return $home_url;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
private function request_uri_begins_with_lang() {
|
||||
$active_lang_codes = array_keys( $this->sitepress->get_active_languages() );
|
||||
$uri_parts = explode( '/', trim( wpml_parse_url( $this->uri_without_subdir, PHP_URL_PATH ), '/' ) );
|
||||
|
||||
return isset( $uri_parts[0] ) && in_array( $uri_parts[0], $active_lang_codes, true );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
<?php
|
||||
|
||||
use WPML\API\Sanitize;
|
||||
|
||||
class WPML_XDomain_Data_Parser {
|
||||
|
||||
const SCRIPT_HANDLER = 'wpml-xdomain-data';
|
||||
|
||||
/**
|
||||
* @var array $settings
|
||||
*/
|
||||
private $settings;
|
||||
|
||||
private $encryptor;
|
||||
|
||||
|
||||
/**
|
||||
* WPML_XDomain_Data_Parser constructor.
|
||||
*
|
||||
* @param array<string,mixed> $settings
|
||||
* @param \WPML_Data_Encryptor $encryptor
|
||||
*/
|
||||
public function __construct( &$settings, $encryptor ) {
|
||||
$this->settings = &$settings;
|
||||
$this->encryptor = $encryptor;
|
||||
}
|
||||
|
||||
public function init_hooks() {
|
||||
if ( ! isset( $this->settings['xdomain_data'] ) || $this->settings['xdomain_data'] != WPML_XDOMAIN_DATA_OFF ) {
|
||||
add_action( 'init', array( $this, 'init' ) );
|
||||
add_filter( 'wpml_get_cross_domain_language_data', array( $this, 'get_xdomain_data' ) );
|
||||
add_filter( 'wpml_get_cross_domain_language_data', array( $this, 'get_xdomain_data' ) );
|
||||
}
|
||||
}
|
||||
|
||||
public function init() {
|
||||
add_action( 'wp_ajax_switching_language', array( $this, 'send_xdomain_language_data' ) );
|
||||
add_action( 'wp_ajax_nopriv_switching_language', array( $this, 'send_xdomain_language_data' ) );
|
||||
add_action( 'wp_enqueue_scripts', array( $this, 'register_scripts_action' ), 100 );
|
||||
}
|
||||
|
||||
public function register_scripts_action() {
|
||||
if ( ! defined( 'DOING_AJAX' ) || ! DOING_AJAX ) {
|
||||
|
||||
$ls_parameters = WPML_Language_Switcher::parameters();
|
||||
|
||||
$js_xdomain_data = array(
|
||||
'css_selector' => $ls_parameters['css_prefix'] . 'item',
|
||||
'ajax_url' => admin_url( 'admin-ajax.php' ),
|
||||
'current_lang' => apply_filters( 'wpml_current_language', '' ),
|
||||
);
|
||||
|
||||
wp_enqueue_script( self::SCRIPT_HANDLER, ICL_PLUGIN_URL . '/res/js/xdomain-data.js', array( 'jquery' ), ICL_SITEPRESS_VERSION );
|
||||
wp_localize_script( self::SCRIPT_HANDLER, 'wpml_xdomain_data', $js_xdomain_data );
|
||||
}
|
||||
}
|
||||
|
||||
public function set_up_xdomain_language_data() {
|
||||
$ret = array();
|
||||
|
||||
$data = apply_filters( 'WPML_cross_domain_language_data', array() );
|
||||
$data = apply_filters( 'wpml_cross_domain_language_data', $data );
|
||||
|
||||
if ( ! empty( $data ) ) {
|
||||
$encoded_data = json_encode( $data );
|
||||
$encoded_data = $this->encryptor->encrypt( $encoded_data );
|
||||
$base64_encoded_data = base64_encode( $encoded_data );
|
||||
$ret['xdomain_data'] = urlencode( $base64_encoded_data );
|
||||
|
||||
$ret['method'] = WPML_XDOMAIN_DATA_POST == $this->settings['xdomain_data'] ? 'post' : 'get';
|
||||
|
||||
}
|
||||
|
||||
return $ret;
|
||||
|
||||
}
|
||||
|
||||
public function send_xdomain_language_data() {
|
||||
|
||||
$data = $this->set_up_xdomain_language_data();
|
||||
|
||||
wp_send_json_success( $data );
|
||||
|
||||
}
|
||||
|
||||
public function get_xdomain_data() {
|
||||
$xdomain_data = array();
|
||||
|
||||
if ( isset( $_GET['xdomain_data'] ) || isset( $_POST['xdomain_data'] ) ) {
|
||||
|
||||
$xdomain_data_request = false;
|
||||
|
||||
if ( WPML_XDOMAIN_DATA_GET == $this->settings['xdomain_data'] ) {
|
||||
$xdomain_data_request = Sanitize::stringProp( 'xdomain_data', $_GET );
|
||||
} elseif ( WPML_XDOMAIN_DATA_POST == $this->settings['xdomain_data'] ) {
|
||||
$xdomain_data_request = urldecode( Sanitize::stringProp( 'xdomain_data', $_POST ) );
|
||||
}
|
||||
|
||||
if ( $xdomain_data_request ) {
|
||||
$data = base64_decode( $xdomain_data_request );
|
||||
$data = $this->encryptor->decrypt( $data );
|
||||
$xdomain_data = (array) json_decode( $data, true );
|
||||
}
|
||||
}
|
||||
return $xdomain_data;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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 );
|
||||
}
|
||||
}
|
||||
@@ -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()
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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 );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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 );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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( '&_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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
class WPML_Resolve_Object_Url_Helper_Factory {
|
||||
|
||||
const CURRENT_URL_RESOLVER = 'current';
|
||||
const ABSOLUTE_URL_RESOLVER = 'absolute';
|
||||
|
||||
/**
|
||||
* @return IWPML_Resolve_Object_Url
|
||||
*/
|
||||
public function create( $type = self::CURRENT_URL_RESOLVER ) {
|
||||
global $sitepress, $wp_query, $wpml_term_translations, $wpml_post_translations;
|
||||
|
||||
if ( self::CURRENT_URL_RESOLVER === $type ) {
|
||||
return new WPML_Resolve_Object_Url_Helper( $sitepress, $wp_query, $wpml_term_translations, $wpml_post_translations );
|
||||
}
|
||||
|
||||
if ( self::ABSOLUTE_URL_RESOLVER === $type ) {
|
||||
$absolute_links = new AbsoluteLinks();
|
||||
$absolute_to_permalinks = new WPML_Absolute_To_Permalinks( $sitepress );
|
||||
|
||||
$translate_links_target = new WPML_Translate_Link_Targets( $absolute_links, $absolute_to_permalinks );
|
||||
|
||||
$resolve_url = new WPML_Resolve_Absolute_Url( $sitepress, $translate_links_target );
|
||||
$url_persisted = WPML_Absolute_Url_Persisted::get_instance();
|
||||
|
||||
return new WPML_Resolve_Absolute_Url_Cached( $url_persisted, $resolve_url );
|
||||
}
|
||||
|
||||
throw new InvalidArgumentException( 'Unknown Resolve_Object_Url type: ' . $type );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,125 @@
|
||||
<?php
|
||||
|
||||
class WPML_Resolve_Object_Url_Helper implements IWPML_Resolve_Object_Url {
|
||||
const CACHE_GROUP = 'resolve_object_url';
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
protected $lock = false;
|
||||
|
||||
/**
|
||||
* @var SitePress
|
||||
*/
|
||||
private $sitepress;
|
||||
|
||||
/**
|
||||
* @var WP_Query
|
||||
*/
|
||||
private $wp_query;
|
||||
|
||||
/**
|
||||
* @var WPML_Term_Translation
|
||||
*/
|
||||
private $wpml_term_translations;
|
||||
|
||||
/**
|
||||
* @var WPML_Post_Translation
|
||||
*/
|
||||
private $wpml_post_translations;
|
||||
|
||||
/**
|
||||
* @param SitePress $sitepress
|
||||
* @param WP_Query $wp_query
|
||||
* @param WPML_Term_Translation $wpml_term_translations
|
||||
* @param WPML_Post_Translation $wpml_post_translations
|
||||
*/
|
||||
public function __construct(
|
||||
SitePress &$sitepress = null,
|
||||
WP_Query &$wp_query = null,
|
||||
WPML_Term_Translation $wpml_term_translations = null,
|
||||
WPML_Post_Translation $wpml_post_translations = null
|
||||
) {
|
||||
$this->sitepress = &$sitepress;
|
||||
$this->wp_query = &$wp_query;
|
||||
$this->wpml_term_translations = $wpml_term_translations;
|
||||
$this->wpml_post_translations = $wpml_post_translations;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Try to parse the URL to find a related post or term
|
||||
*
|
||||
* @param string $url
|
||||
* @param string $lang_code
|
||||
*
|
||||
* @return string|bool
|
||||
*/
|
||||
public function resolve_object_url( $url, $lang_code ) {
|
||||
if ( $this->lock ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->lock = true;
|
||||
$new_url = false;
|
||||
|
||||
$translations = $this->cached_retrieve_translations( $url );
|
||||
if ( $translations && isset( $translations[ $lang_code ]->element_type ) ) {
|
||||
|
||||
$current_lang = $this->sitepress->get_current_language();
|
||||
$this->sitepress->switch_lang( $lang_code );
|
||||
|
||||
$element = explode( '_', $translations[ $lang_code ]->element_type );
|
||||
$type = array_shift( $element );
|
||||
$subtype = implode( '_', $element );
|
||||
switch ( $type ) {
|
||||
case 'post':
|
||||
$new_url = get_permalink( $translations[ $lang_code ]->element_id );
|
||||
break;
|
||||
case 'tax':
|
||||
$term = get_term_by( 'term_taxonomy_id', $translations[ $lang_code ]->element_id, $subtype );
|
||||
$new_url = get_term_link( $term );
|
||||
break;
|
||||
}
|
||||
|
||||
$this->sitepress->switch_lang( $current_lang );
|
||||
}
|
||||
|
||||
$this->lock = false;
|
||||
return $new_url;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $url
|
||||
*
|
||||
* @return array<string,\stdClass>
|
||||
*/
|
||||
private function cached_retrieve_translations( $url ) {
|
||||
$cache_key = md5( $url );
|
||||
$cache_found = false;
|
||||
$cache = new WPML_WP_Cache( self::CACHE_GROUP );
|
||||
$translations = $cache->get( $cache_key, $cache_found );
|
||||
|
||||
if ( ! $cache_found && is_object( $this->wp_query ) ) {
|
||||
$translations = $this->retrieve_translations();
|
||||
$cache->set( $cache_key, $translations );
|
||||
}
|
||||
|
||||
return $translations;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string,\stdClass>
|
||||
*/
|
||||
private function retrieve_translations() {
|
||||
$this->sitepress->set_wp_query(); // Make sure $sitepress->wp_query is set
|
||||
$_wp_query_back = clone $this->wp_query;
|
||||
$wp_query = $this->sitepress->get_wp_query();
|
||||
$wp_query = is_object( $wp_query ) ? clone $wp_query : clone $_wp_query_back;
|
||||
|
||||
$languages_helper = new WPML_Languages( $this->wpml_term_translations, $this->sitepress, $this->wpml_post_translations );
|
||||
list( $translations) = $languages_helper->get_ls_translations( $wp_query, $_wp_query_back, $this->sitepress->get_wp_query() );
|
||||
|
||||
return $translations;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
class WPML_Absolute_Url_Persisted_Filters_Factory implements IWPML_Backend_Action_Loader, IWPML_AJAX_Action_Loader {
|
||||
|
||||
public function create() {
|
||||
$url_persisted = WPML_Absolute_Url_Persisted::get_instance();
|
||||
|
||||
if ( $url_persisted->has_urls() ) {
|
||||
return new WPML_Absolute_Url_Persisted_Filters( $url_persisted );
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
class WPML_Absolute_Url_Persisted_Filters implements IWPML_Action {
|
||||
|
||||
/** @var WPML_Absolute_Url_Persisted $url_persisted */
|
||||
private $url_persisted;
|
||||
|
||||
public function __construct( WPML_Absolute_Url_Persisted $url_persisted ) {
|
||||
$this->url_persisted = $url_persisted;
|
||||
}
|
||||
|
||||
public function add_hooks() {
|
||||
add_filter( 'wp_insert_post_data', [ $this, 'reset' ] );
|
||||
add_action( 'delete_post', [ $this, 'reset' ] );
|
||||
|
||||
add_filter( 'wp_update_term_data', [ $this, 'reset' ] );
|
||||
add_action( 'pre_delete_term', [ $this, 'reset' ] );
|
||||
|
||||
add_filter( 'rewrite_rules_array', [ $this, 'reset' ] );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $data
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function reset( $data = null ) {
|
||||
$this->url_persisted->reset();
|
||||
return $data;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
<?php
|
||||
|
||||
interface IWPML_Resolve_Object_Url {
|
||||
|
||||
/**
|
||||
* @param string $url
|
||||
* @param string $lang
|
||||
*
|
||||
* @return string|false Will return the resolved URL or `false` if it could not be resolved.
|
||||
*/
|
||||
public function resolve_object_url( $url, $lang );
|
||||
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
<?php
|
||||
|
||||
class WPML_Absolute_Url_Persisted {
|
||||
|
||||
const OPTION_KEY = 'wpml_resolved_url_persist';
|
||||
|
||||
private static $instance;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private $urls;
|
||||
|
||||
/**
|
||||
* @return WPML_Absolute_Url_Persisted
|
||||
*/
|
||||
public static function get_instance() {
|
||||
if ( null === self::$instance ) {
|
||||
self::$instance = new self();
|
||||
}
|
||||
|
||||
return self::$instance;
|
||||
}
|
||||
|
||||
protected function __construct() {}
|
||||
|
||||
private function __clone() {}
|
||||
|
||||
/**
|
||||
* @throws Exception
|
||||
*/
|
||||
public function __wakeup() {
|
||||
throw new Exception( 'Cannot unserialize singleton' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns urls array.
|
||||
*
|
||||
* @return array Array with urls.
|
||||
*/
|
||||
private function get_urls() {
|
||||
if ( null === $this->urls ) {
|
||||
$this->urls = get_option( self::OPTION_KEY, array() );
|
||||
|
||||
if ( ! is_array( $this->urls ) ) {
|
||||
$this->urls = array();
|
||||
}
|
||||
}
|
||||
|
||||
return $this->urls;
|
||||
}
|
||||
|
||||
/** @return bool */
|
||||
public function has_urls() {
|
||||
return (bool) $this->get_urls();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $original_url
|
||||
* @param string $lang
|
||||
* @param string|false $converted_url A `false` value means that the URL could not be resolved
|
||||
*/
|
||||
public function set( $original_url, $lang, $converted_url ) {
|
||||
$this->get_urls();
|
||||
$this->urls[ $original_url ][ $lang ] = $converted_url;
|
||||
$this->persist_in_shutdown();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $original_url
|
||||
* @param string $lang
|
||||
*
|
||||
* @return string|false|null If the URL has already been processed but could not be resolved, it will return `false`
|
||||
*/
|
||||
public function get( $original_url, $lang ) {
|
||||
$this->get_urls();
|
||||
|
||||
if ( isset( $this->urls[ $original_url ][ $lang ] ) ) {
|
||||
return $this->urls[ $original_url ][ $lang ];
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public function reset() {
|
||||
$this->urls = [];
|
||||
$this->persist();
|
||||
$this->urls = null;
|
||||
}
|
||||
|
||||
public function persist() {
|
||||
update_option( self::OPTION_KEY, $this->urls );
|
||||
}
|
||||
|
||||
private function persist_in_shutdown() {
|
||||
if ( ! has_action( 'shutdown', array( $this, 'persist' ) ) ) {
|
||||
add_action( 'shutdown', array( $this, 'persist' ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
class WPML_Resolve_Absolute_Url_Cached implements IWPML_Resolve_Object_Url {
|
||||
|
||||
/** @var WPML_Absolute_Url_Persisted $url_persisted */
|
||||
private $url_persisted;
|
||||
|
||||
/** @var WPML_Resolve_Absolute_Url $resolve_url */
|
||||
private $resolve_url;
|
||||
|
||||
public function __construct( WPML_Absolute_Url_Persisted $url_persisted, WPML_Resolve_Absolute_Url $resolve_url ) {
|
||||
$this->url_persisted = $url_persisted;
|
||||
$this->resolve_url = $resolve_url;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $url
|
||||
* @param string $lang
|
||||
*
|
||||
* @return false|string Will return `false` if the URL could not be resolved
|
||||
*/
|
||||
public function resolve_object_url( $url, $lang ) {
|
||||
$resolved_url = $this->url_persisted->get( $url, $lang );
|
||||
|
||||
if ( null === $resolved_url ) {
|
||||
$resolved_url = $this->resolve_url->resolve_object_url( $url, $lang );
|
||||
$this->url_persisted->set( $url, $lang, $resolved_url );
|
||||
}
|
||||
|
||||
return $resolved_url;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
<?php
|
||||
|
||||
class WPML_Resolve_Absolute_Url implements IWPML_Resolve_Object_Url {
|
||||
|
||||
/** @var SitePress $sitepress */
|
||||
private $sitepress;
|
||||
|
||||
/** @var WPML_Translate_Link_Targets */
|
||||
private $translate_link_targets;
|
||||
|
||||
/** @var bool */
|
||||
private $lock;
|
||||
|
||||
public function __construct( SitePress $sitepress, WPML_Translate_Link_Targets $translate_link_targets ) {
|
||||
$this->sitepress = $sitepress;
|
||||
$this->translate_link_targets = $translate_link_targets;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $url
|
||||
* @param string $lang
|
||||
*
|
||||
* @return string|false
|
||||
*/
|
||||
public function resolve_object_url( $url, $lang ) {
|
||||
if ( $this->lock ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->lock = true;
|
||||
$current_lang = $this->sitepress->get_current_language();
|
||||
$this->sitepress->switch_lang( $lang );
|
||||
|
||||
try {
|
||||
$new_url = $this->translate_link_targets->convert_url( $url );
|
||||
|
||||
if ( trailingslashit( $new_url ) === trailingslashit( $url ) ) {
|
||||
$new_url = false;
|
||||
}
|
||||
} catch ( Exception $e ) {
|
||||
$new_url = false;
|
||||
}
|
||||
|
||||
$this->sitepress->switch_lang( $current_lang );
|
||||
$this->lock = false;
|
||||
|
||||
return $new_url;
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,454 @@
|
||||
<?php
|
||||
|
||||
use \WPML\FP\Str;
|
||||
use \WPML\SuperGlobals\Server;
|
||||
|
||||
/**
|
||||
* Class WPML_URL_Filters
|
||||
*/
|
||||
class WPML_URL_Filters {
|
||||
/** @var \SitePress */
|
||||
private $sitepress;
|
||||
|
||||
/** @var \WPML_Post_Translation $post_translation */
|
||||
private $post_translation;
|
||||
|
||||
/** @var \WPML_Canonicals */
|
||||
private $canonicals;
|
||||
|
||||
/** @var \WPML_URL_Converter $url_converter */
|
||||
private $url_converter;
|
||||
|
||||
/** @var \WPML_Debug_BackTrace */
|
||||
private $debug_backtrace;
|
||||
|
||||
/**
|
||||
* WPML_URL_Filters constructor.
|
||||
*
|
||||
* @param \WPML_Post_Translation $post_translation
|
||||
* @param string $url_converter
|
||||
* @param \WPML_Canonicals $canonicals
|
||||
* @param \SitePress $sitepress
|
||||
* @param \WPML_Debug_BackTrace $debug_backtrace
|
||||
*/
|
||||
public function __construct(
|
||||
&$post_translation,
|
||||
&$url_converter,
|
||||
WPML_Canonicals $canonicals,
|
||||
&$sitepress,
|
||||
WPML_Debug_BackTrace $debug_backtrace
|
||||
) {
|
||||
$this->sitepress = &$sitepress;
|
||||
$this->post_translation = &$post_translation;
|
||||
|
||||
$this->url_converter = &$url_converter;
|
||||
$this->canonicals = $canonicals;
|
||||
$this->debug_backtrace = $debug_backtrace;
|
||||
|
||||
if ( $this->frontend_uses_root() === true ) {
|
||||
WPML_Root_Page::init();
|
||||
}
|
||||
$this->add_hooks();
|
||||
}
|
||||
|
||||
private function add_hooks() {
|
||||
if ( $this->frontend_uses_root() === true ) {
|
||||
add_filter( 'page_link', array( $this, 'page_link_filter_root' ), 1, 2 );
|
||||
} else {
|
||||
add_filter( 'page_link', array( $this, 'page_link_filter' ), 1, 2 );
|
||||
}
|
||||
|
||||
$this->add_global_hooks();
|
||||
if ( $this->has_wp_get_canonical_url() ) {
|
||||
add_filter( 'get_canonical_url', array( $this, 'get_canonical_url_filter' ), 1, 2 );
|
||||
}
|
||||
}
|
||||
|
||||
public function add_global_hooks() {
|
||||
add_filter( 'home_url', [ $this, 'home_url_filter' ], - 10, 4 );
|
||||
// posts, pages & attachments links filters
|
||||
add_filter( 'post_link', [ $this, 'permalink_filter' ], 1, 2 );
|
||||
add_filter( 'attachment_link', [ $this, 'permalink_filter' ], 1, 2 );
|
||||
add_filter( 'post_type_link', [ $this, 'permalink_filter' ], 1, 2 );
|
||||
add_filter( 'wpml_filter_link', [ $this, 'permalink_filter' ], 1, 2 );
|
||||
add_filter( 'get_edit_post_link', [ $this, 'get_edit_post_link' ], 1, 3 );
|
||||
add_filter( 'oembed_request_post_id', [ $this, 'embedded_front_page_id_filter' ], 1, 2 );
|
||||
add_filter( 'post_embed_url', [ $this, 'fix_post_embedded_url' ], 1, 1 );
|
||||
|
||||
}
|
||||
|
||||
public function remove_global_hooks() {
|
||||
// posts and pages links filters
|
||||
remove_filter( 'oembed_request_post_id', [ $this, 'embedded_front_page_id_filter' ], 1 );
|
||||
remove_filter( 'post_embed_url', [ $this, 'fix_post_embedded_url' ], 1 );
|
||||
remove_filter( 'get_edit_post_link', [ $this, 'get_edit_post_link' ], 1 );
|
||||
remove_filter( 'wpml_filter_link', [ $this, 'permalink_filter' ], 1 );
|
||||
remove_filter( 'post_type_link', [ $this, 'permalink_filter' ], 1 );
|
||||
remove_filter( 'attachment_link', [ $this, 'permalink_filter' ], 1 );
|
||||
remove_filter( 'post_link', [ $this, 'permalink_filter' ], 1 );
|
||||
|
||||
remove_filter( 'home_url', [ $this, 'home_url_filter' ], - 10 );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $post_id
|
||||
* @param string $url
|
||||
*
|
||||
* @return int
|
||||
*
|
||||
* @hook oembed_request_post_id
|
||||
*/
|
||||
public function embedded_front_page_id_filter( $post_id, $url ) {
|
||||
if ( ! $post_id && $this->is_front_page( $url ) ) {
|
||||
$page_on_front = get_option( 'page_on_front' );
|
||||
|
||||
if ( $page_on_front && get_post( $page_on_front ) instanceof WP_Post ) {
|
||||
$post_id = (int) $page_on_front;
|
||||
}
|
||||
}
|
||||
|
||||
return $post_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $embedded_url
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function fix_post_embedded_url( $embedded_url ) {
|
||||
$query = wpml_parse_url( $embedded_url, PHP_URL_QUERY );
|
||||
$embed = user_trailingslashit( 'embed' );
|
||||
if ( Str::includes( $embed, $query ) ) {
|
||||
$embedded_url = Str::split( '?', $embedded_url )[0] . $embed . '?' .
|
||||
untrailingslashit( Str::replace( $embed, '', $query ) );
|
||||
}
|
||||
|
||||
return $embedded_url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Filters the link to a post's edit screen by appending the language query argument
|
||||
*
|
||||
* @param string $link
|
||||
* @param int $id
|
||||
* @param string $context
|
||||
*
|
||||
* @return string
|
||||
*
|
||||
* @hook get_edit_post_link
|
||||
*/
|
||||
public function get_edit_post_link( $link, $id, $context = 'display' ) {
|
||||
if ( $id && (bool) ( $lang = $this->post_translation->get_element_lang_code( $id ) ) === true ) {
|
||||
$link .= ( 'display' === $context ? '&' : '&' ) . 'lang=' . $lang;
|
||||
if ( ! did_action( 'wpml_pre_status_icon_display' ) ) {
|
||||
do_action( 'wpml_pre_status_icon_display' );
|
||||
}
|
||||
$link = apply_filters( 'wpml_link_to_translation', $link, $id, $lang, $this->post_translation->get_element_trid( $id ) );
|
||||
}
|
||||
|
||||
return $link;
|
||||
}
|
||||
|
||||
/**
|
||||
* Permalink filter that is used when the site uses a root page
|
||||
*
|
||||
* @param string $link
|
||||
* @param int|WP_Post $pid
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function permalink_filter_root( $link, $pid ) {
|
||||
$pid = is_object( $pid ) ? $pid->ID : $pid;
|
||||
$link = $this->sitepress->get_root_page_utils()->get_root_page_id() != $pid
|
||||
? $this->permalink_filter( $link, $pid ) : $this->filter_root_permalink( $link );
|
||||
|
||||
return $link;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $link
|
||||
* @param int $pid
|
||||
*
|
||||
* @return string|WPML_Notice|WPML_Notice_Render
|
||||
*/
|
||||
public function page_link_filter_root( $link, $pid ) {
|
||||
$pid = is_object( $pid ) ? $pid->ID : $pid;
|
||||
$link = $this->sitepress->get_root_page_utils()->get_root_page_id() != $pid
|
||||
? $this->page_link_filter( $link, $pid ) : $this->filter_root_permalink( $link );
|
||||
|
||||
return $link;
|
||||
}
|
||||
|
||||
/**
|
||||
* Filters links to the root page, so that they are displayed properly in the front-end.
|
||||
*
|
||||
* @param string $url
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function filter_root_permalink( $url ) {
|
||||
$root_page_utils = $this->sitepress->get_root_page_utils();
|
||||
if ( $root_page_utils->get_root_page_id() > 0 && $root_page_utils->is_url_root_page( $url ) ) {
|
||||
$url_parts = wpml_parse_url( $url );
|
||||
$query = isset( $url_parts['query'] ) ? $url_parts['query'] : '';
|
||||
$path = isset( $url_parts['path'] ) ? $url_parts['path'] : '';
|
||||
$slugs = array_filter( explode( '/', $path ) );
|
||||
$last_slug = array_pop( $slugs );
|
||||
$new_url = $this->url_converter->get_abs_home();
|
||||
$new_url = is_numeric( $last_slug ) ? trailingslashit( trailingslashit( $new_url ) . $last_slug ) : $new_url;
|
||||
$query = $this->unset_page_query_vars( $query );
|
||||
$new_url = trailingslashit( $new_url );
|
||||
$url = (bool) $query === true ? trailingslashit( $new_url ) . '?' . $query : $new_url;
|
||||
}
|
||||
|
||||
return $url;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $link
|
||||
* @param int|WP_Post $post
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function permalink_filter( $link, $post ) {
|
||||
if ( ! $post ) {
|
||||
return $link;
|
||||
}
|
||||
|
||||
$post_id = $post;
|
||||
|
||||
if ( is_object( $post ) ) {
|
||||
$post_id = $post->ID;
|
||||
}
|
||||
|
||||
/** @var int $post_id */
|
||||
if ( $post_id < 1 ) {
|
||||
return $link;
|
||||
}
|
||||
|
||||
$canonical_url = $this->canonicals->permalink_filter( $link, $post_id );
|
||||
if ( $canonical_url ) {
|
||||
return $canonical_url;
|
||||
}
|
||||
|
||||
$post_element = new WPML_Post_Element( $post_id, $this->sitepress );
|
||||
if ( ! $this->is_display_as_translated_mode( $post_element ) && $post_element->is_translatable() ) {
|
||||
$link = $this->get_translated_permalink( $link, $post_id, $post_element );
|
||||
}
|
||||
|
||||
return $this->url_converter->get_strategy()->fix_trailingslashit( $link );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $link
|
||||
* @param int|WP_Post $post
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function page_link_filter( $link, $post ) {
|
||||
return $this->permalink_filter( $link, $post );
|
||||
}
|
||||
|
||||
private function has_wp_get_canonical_url() {
|
||||
return $this->sitepress->get_wp_api()->function_exists( 'wp_get_canonical_url' );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string|bool $canonical_url
|
||||
* @param WP_Post $post
|
||||
*
|
||||
* @return mixed
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
public function get_canonical_url_filter( $canonical_url, $post ) {
|
||||
return $this->canonicals->get_canonical_url( $canonical_url, $post, $this->get_request_language() );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $url
|
||||
* @param string $path
|
||||
* @param string $orig_scheme
|
||||
* @param int $blog_id
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function home_url_filter( $url, $path, $orig_scheme, $blog_id ) {
|
||||
$language_negotiation_type = (int) $this->sitepress->get_setting( 'language_negotiation_type' );
|
||||
|
||||
$context = new WPML_Home_Url_Filter_Context(
|
||||
$language_negotiation_type,
|
||||
$orig_scheme,
|
||||
$this->debug_backtrace
|
||||
);
|
||||
|
||||
if ( $context->should_not_filter() ) {
|
||||
return $url;
|
||||
}
|
||||
|
||||
$url_language = $this->get_request_language();
|
||||
|
||||
if ( 'relative' === $orig_scheme ) {
|
||||
$home_url = $this->url_converter->get_home_url_relative( $url, $url_language );
|
||||
} else {
|
||||
$home_url = $this->url_converter->convert_url( $url, $url_language );
|
||||
}
|
||||
|
||||
$home_url = apply_filters( 'wpml_get_home_url', $home_url, $url, $path, $orig_scheme, $blog_id );
|
||||
|
||||
return $home_url;
|
||||
}
|
||||
|
||||
public function frontend_uses_root() {
|
||||
/** @var array $urls */
|
||||
$urls = $this->sitepress->get_setting( 'urls' );
|
||||
|
||||
if ( is_admin() ) {
|
||||
$uses_root = isset( $urls['root_page'], $urls['show_on_root'] )
|
||||
&& ! empty( $urls['directory_for_default_language'] )
|
||||
&& ( in_array( $urls['show_on_root'], array( 'page', 'html_file' ) ) );
|
||||
} else {
|
||||
$uses_root = isset( $urls['root_page'], $urls['show_on_root'] )
|
||||
&& ! empty( $urls['directory_for_default_language'] )
|
||||
&& ( ( $urls['root_page'] > 0 && 'page' === $urls['show_on_root'] )
|
||||
|| ( $urls['root_html_file_path'] && 'html_file' === $urls['show_on_root'] ) );
|
||||
}
|
||||
|
||||
return $uses_root;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the correct language a post belongs to by handling the special case of the post edit screen.
|
||||
*
|
||||
* @param int $post_id
|
||||
*
|
||||
* @return bool|mixed|null|String
|
||||
*/
|
||||
private function get_permalink_filter_lang( $post_id ) {
|
||||
if ( isset( $_POST['action'] ) && $_POST['action'] === 'sample-permalink' ) {
|
||||
$code = $this->get_language_from_url();
|
||||
$code = $code
|
||||
? $code
|
||||
: ( ! isset( $_SERVER['HTTP_REFERER'] )
|
||||
? $this->sitepress->get_default_language()
|
||||
: $this->url_converter->get_language_from_url( $_SERVER['HTTP_REFERER'] ) );
|
||||
} else {
|
||||
$code = $this->post_translation->get_element_lang_code( $post_id );
|
||||
}
|
||||
|
||||
return $code;
|
||||
}
|
||||
|
||||
private function unset_page_query_vars( $query ) {
|
||||
parse_str( (string) $query, $query_parts );
|
||||
foreach ( array( 'p', 'page_id', 'page', 'pagename', 'page_name', 'attachement_id' ) as $part ) {
|
||||
if ( isset( $query_parts[ $part ] ) && ! ( $part === 'page_id' && ! empty( $query_parts['preview'] ) ) ) {
|
||||
unset( $query_parts[ $part ] );
|
||||
}
|
||||
}
|
||||
|
||||
return http_build_query( $query_parts );
|
||||
}
|
||||
|
||||
private function get_language_from_url( $return_default_language_if_missing = false ) {
|
||||
$query_string_argument = '';
|
||||
$language = '';
|
||||
if ( $return_default_language_if_missing ) {
|
||||
$language = $this->sitepress->get_current_language();
|
||||
}
|
||||
if ( array_key_exists( 'wpml_lang', $_GET ) ) {
|
||||
$query_string_argument = 'wpml_lang';
|
||||
} elseif ( array_key_exists( 'lang', $_GET ) ) {
|
||||
$query_string_argument = 'lang';
|
||||
}
|
||||
if ( '' !== $query_string_argument ) {
|
||||
$language = filter_var( $_GET[ $query_string_argument ], FILTER_SANITIZE_FULL_SPECIAL_CHARS );
|
||||
}
|
||||
|
||||
return $language;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $link
|
||||
* @param int $post
|
||||
* @param WPML_Post_Element $post_element
|
||||
*
|
||||
* @return bool|false|mixed|string
|
||||
*/
|
||||
public function get_translated_permalink( $link, $post, $post_element ) {
|
||||
$code = $this->get_permalink_filter_lang( $post );
|
||||
$force_translate_permalink = apply_filters( 'wpml_force_translated_permalink', false );
|
||||
|
||||
if ( ( ! is_admin() || wp_doing_ajax() || wpml_is_ajax() || $force_translate_permalink )
|
||||
&& ( ! $this->sitepress->get_wp_api()->is_a_REST_request() || $force_translate_permalink )
|
||||
&& $this->should_use_permalink_of_post_translation( $post_element )
|
||||
) {
|
||||
$link = get_permalink( $this->get_translated_post_id_for_current_language( $post_element ) );
|
||||
} else {
|
||||
$link = $this->url_converter->get_strategy()->convert_url_string( $link, $code );
|
||||
}
|
||||
if ( $this->sitepress->get_wp_api()->is_feed() ) {
|
||||
$link = str_replace( '&lang=', '&lang=', $link );
|
||||
}
|
||||
|
||||
return $link;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $link
|
||||
* @param int $post_id
|
||||
* @param \WPML_Post_Element $post_element
|
||||
*
|
||||
* @return bool|mixed|string
|
||||
*/
|
||||
public function get_translated_page_link( $link, $post_id, $post_element ) {
|
||||
$code = $this->get_permalink_filter_lang( $post_id );
|
||||
if ( ! is_admin() && $this->should_use_permalink_of_post_translation( $post_element ) ) {
|
||||
$link = get_page_link( $this->get_translated_post_id_for_current_language( $post_element ) );
|
||||
} else {
|
||||
$link = $this->url_converter->get_strategy()->convert_url_string( $link, $code );
|
||||
}
|
||||
if ( $this->sitepress->get_wp_api()->is_feed() ) {
|
||||
$link = str_replace( '&lang=', '&lang=', $link );
|
||||
}
|
||||
|
||||
return $link;
|
||||
}
|
||||
|
||||
public function get_request_language() {
|
||||
$request_uri = isset( $_SERVER['REQUEST_URI'] ) ? $_SERVER['REQUEST_URI'] : '';
|
||||
$server_name = strpos( $request_uri, '/' ) === 0
|
||||
? untrailingslashit( Server::getServerName() ) : trailingslashit( Server::getServerName() );
|
||||
$url_snippet = $server_name . $request_uri;
|
||||
|
||||
return $this->url_converter->get_language_from_url( $url_snippet );
|
||||
}
|
||||
|
||||
private function should_use_permalink_of_post_translation( WPML_Post_Element $post_element ) {
|
||||
return $this->sitepress->get_setting( 'auto_adjust_ids' )
|
||||
&& $post_element->get_language_code() !== $this->sitepress->get_current_language()
|
||||
&& $this->get_translated_post_id_for_current_language( $post_element );
|
||||
}
|
||||
|
||||
private function is_display_as_translated_mode( WPML_Post_Element $post_element ) {
|
||||
return $post_element->is_display_as_translated() &&
|
||||
$post_element->get_language_code() == $this->sitepress->get_default_language() &&
|
||||
! $this->get_translated_post_id_for_current_language( $post_element ) &&
|
||||
! $this->debug_backtrace->is_class_function_in_call_stack( 'SitePress', 'get_ls_languages' );
|
||||
}
|
||||
|
||||
private function get_translated_post_id_for_current_language( WPML_Post_Element $post_element ) {
|
||||
$post_id = $post_element->get_element_id();
|
||||
$current_language = $this->sitepress->get_current_language();
|
||||
|
||||
return $this->post_translation->element_id_in( $post_id, $current_language );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $url
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function is_front_page( $url ) {
|
||||
return $this->canonicals->get_general_canonical_url( $url ) === home_url() && 'page' === get_option( 'show_on_front' );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
namespace WPML\UrlHandling;
|
||||
|
||||
class WPLoginUrlConverterFactory implements \IWPML_Frontend_Action_Loader, \IWPML_Backend_Action_Loader {
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function create() {
|
||||
/** @var \WPML_URL_Converter $wpml_url_converter */
|
||||
global $wpml_url_converter, $sitepress;
|
||||
|
||||
$rules = new WPLoginUrlConverterRules();
|
||||
|
||||
return WPLoginUrlConverter::isEnabled()
|
||||
? array_filter( [ $wpml_url_converter->get_wp_login_url_converter( $sitepress ), $rules ] )
|
||||
: [ $rules ];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,279 @@
|
||||
<?php
|
||||
|
||||
namespace WPML\UrlHandling;
|
||||
|
||||
use WPML\API\Sanitize;
|
||||
use WPML\Element\API\Languages;
|
||||
use WPML\FP\Obj;
|
||||
use WPML\FP\Relation;
|
||||
use WPML\FP\Str;
|
||||
use WPML\LIB\WP\Option;
|
||||
use WPML\LIB\WP\User;
|
||||
|
||||
class WPLoginUrlConverter implements \IWPML_Action {
|
||||
const PRIORITY_AFTER_URL_FILTERS = 100;
|
||||
const SETTINGS_KEY = 'wpml_login_page_translation';
|
||||
|
||||
private $rewrite_rule_not_found;
|
||||
|
||||
/** @var \WPML_URL_Converter $url_converter */
|
||||
private $url_converter;
|
||||
|
||||
/** @var \SitePress $sitepress */
|
||||
private $sitepress;
|
||||
|
||||
/**
|
||||
* @param \WPML_URL_Converter $url_converter
|
||||
* @param \SitePress $sitepress
|
||||
*/
|
||||
public function __construct( $sitepress, $url_converter ) {
|
||||
$this->rewrite_rule_not_found = false;
|
||||
$this->url_converter = $url_converter;
|
||||
$this->sitepress = $sitepress;
|
||||
}
|
||||
|
||||
public function add_hooks() {
|
||||
add_filter( 'site_url', [ $this, 'site_url' ], self::PRIORITY_AFTER_URL_FILTERS, 3 );
|
||||
add_filter( 'login_url', [ $this, 'convert_url' ] );
|
||||
|
||||
add_filter( 'register_url', [ $this, 'convert_url' ] );
|
||||
add_filter( 'lostpassword_url', [ $this, 'convert_url' ] );
|
||||
add_filter( 'request', [ $this, 'on_request' ] );
|
||||
add_filter(
|
||||
'wpml_get_language_from_url',
|
||||
[
|
||||
$this,
|
||||
'wpml_login_page_language_from_url',
|
||||
],
|
||||
self::PRIORITY_AFTER_URL_FILTERS,
|
||||
2
|
||||
);
|
||||
add_filter( 'registration_redirect', [ $this, 'filter_redirect_with_lang' ] );
|
||||
add_filter( 'lostpassword_redirect', [ $this, 'filter_redirect_with_lang' ] );
|
||||
|
||||
if ( self::isEnabled() ) {
|
||||
add_filter( 'logout_url', [ $this, 'convert_user_logout_url' ] );
|
||||
add_filter( 'logout_redirect', [ $this, 'convert_default_redirect_url' ], 2, 10 );
|
||||
}
|
||||
|
||||
add_action( 'generate_rewrite_rules', [ $this, 'generate_rewrite_rules' ] );
|
||||
add_action( 'login_init', [ $this, 'redirect_to_login_url_with_lang' ] );
|
||||
|
||||
if ( is_multisite() ) {
|
||||
add_filter( 'network_site_url', [ $this, 'site_url' ], self::PRIORITY_AFTER_URL_FILTERS, 3 );
|
||||
add_filter( 'wp_signup_location', [ $this, 'convert_url' ] );
|
||||
add_action( 'signup_hidden_fields', [ $this, 'add_signup_language_field' ] );
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the logout URL to be translated.
|
||||
*
|
||||
* @param string $url
|
||||
* @return string
|
||||
*/
|
||||
public function convert_user_logout_url( $url ) {
|
||||
$current_user_id = User::getCurrentId();
|
||||
if ( $current_user_id ) {
|
||||
$user_locale = User::getMetaSingle( $current_user_id, 'locale' );
|
||||
if ( ! empty( $user_locale ) ) {
|
||||
$language_code = $this->sitepress->get_language_code_from_locale( $user_locale );
|
||||
return $this->url_converter->convert_url( $url, $language_code );
|
||||
}
|
||||
}
|
||||
return $url;
|
||||
}
|
||||
|
||||
public function add_signup_language_field() {
|
||||
echo "<input type='hidden' name='lang' value='" . $this->sitepress->get_current_language() . "' />";
|
||||
}
|
||||
|
||||
public function redirect_to_login_url_with_lang() {
|
||||
$sitePath = Obj::propOr( '', 'path', parse_url( site_url() ) );
|
||||
$requestUriWithoutPath = Str::trimPrefix( $sitePath, $_SERVER['REQUEST_URI'] );
|
||||
|
||||
$converted_url = site_url( $requestUriWithoutPath, 'login' );
|
||||
if (
|
||||
! is_multisite()
|
||||
&& $converted_url != site_url( $requestUriWithoutPath )
|
||||
&& wp_redirect( $converted_url, 302, 'WPML' )
|
||||
) {
|
||||
exit;
|
||||
}
|
||||
}
|
||||
|
||||
public function generate_rewrite_rules() {
|
||||
global $wp_rewrite;
|
||||
|
||||
$language_rules = wpml_collect( Languages::getActive() )->mapWithKeys(
|
||||
function ( $lang ) {
|
||||
return [ $lang['code'] . '/wp-login.php' => 'wp-login.php' ];
|
||||
}
|
||||
);
|
||||
|
||||
$wp_rewrite->non_wp_rules = array_merge( $language_rules->toArray(), $wp_rewrite->non_wp_rules );
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the redirected string if it's the default one.
|
||||
*
|
||||
* @param string $redirect_to
|
||||
* @param string $requested_redirect_to
|
||||
* @return string
|
||||
*/
|
||||
public function convert_default_redirect_url( $redirect_to, $requested_redirect_to ) {
|
||||
if ( '' === $requested_redirect_to ) {
|
||||
return $this->convert_url( $redirect_to );
|
||||
}
|
||||
|
||||
return $redirect_to;
|
||||
}
|
||||
|
||||
public function filter_redirect_with_lang( $redirect_to ) {
|
||||
if ( ! $redirect_to && Obj::prop( 'lang', $_GET ) ) {
|
||||
$redirect_to = site_url( 'wp-login.php?checkemail=confirm', 'login' );
|
||||
}
|
||||
|
||||
return $redirect_to;
|
||||
}
|
||||
|
||||
public function wpml_login_page_language_from_url( $language, $url ) {
|
||||
if ( $this->is_wp_login_url( $url ) ) {
|
||||
if ( isset( $_GET['lang'] ) && $_GET['lang'] != $language ) {
|
||||
return Sanitize::stringProp( 'lang', $_GET );
|
||||
}
|
||||
if ( is_multisite() && isset( $_POST['lang'] ) && $_POST['lang'] != $language ) {
|
||||
return Sanitize::stringProp( 'lang', $_POST );
|
||||
}
|
||||
}
|
||||
|
||||
return $language;
|
||||
}
|
||||
|
||||
public function site_url( $url, $path, $scheme ) {
|
||||
if ( $scheme === 'login_post' || $scheme === 'login' || $this->should_convert_url_for_multisite( $url ) ) {
|
||||
$url = $this->convert_url( $url );
|
||||
}
|
||||
|
||||
return $url;
|
||||
}
|
||||
|
||||
public function convert_url( $url ) {
|
||||
$lang_param = $this->get_language_param_for_convert_url();
|
||||
if ( $lang_param ) {
|
||||
return add_query_arg( 'lang', $lang_param, $url );
|
||||
}
|
||||
|
||||
return $this->url_converter->convert_url( $url );
|
||||
}
|
||||
|
||||
public function on_request( $query_vars ) {
|
||||
if ( Relation::propEq( 'name', 'wp-login.php', $query_vars ) ) {
|
||||
$this->rewrite_rule_not_found = true;
|
||||
} else {
|
||||
$this->rewrite_rule_not_found = false;
|
||||
}
|
||||
|
||||
if ( $this->rewrite_rule_not_found && $this->is_wp_login_action() ) {
|
||||
$current_url = site_url( $_SERVER['REQUEST_URI'], 'login' );
|
||||
$redirect_to = $this->remove_language_directory_from_url( $current_url );
|
||||
|
||||
if (
|
||||
$redirect_to !== $current_url
|
||||
&& wp_redirect( $redirect_to, 302, 'WPML' )
|
||||
) {
|
||||
exit;
|
||||
}
|
||||
}
|
||||
|
||||
return $query_vars;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $validateOrRollback - If true, it will be validated that the translated Login URL is accessible or rollback.
|
||||
* @return void
|
||||
*/
|
||||
public static function enable( $validateOrRollback = false ) {
|
||||
self::saveState( true, $validateOrRollback );
|
||||
}
|
||||
|
||||
public static function disable() {
|
||||
self::saveState( false );
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public static function isEnabled() {
|
||||
return Option::getOr( self::SETTINGS_KEY, false );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $state
|
||||
* @param bool $validate - if true, will validate the change or undo it.
|
||||
*
|
||||
*/
|
||||
public static function saveState( $state, $validate = false ) {
|
||||
Option::update( self::SETTINGS_KEY, $state );
|
||||
WPLoginUrlConverterRules::markRulesForUpdating( $validate );
|
||||
}
|
||||
|
||||
private function should_convert_url_for_multisite( $url ) {
|
||||
return is_multisite() && Str::includes( 'wp-activate.php', $url );
|
||||
}
|
||||
|
||||
private function is_wp_login_url( $url ) {
|
||||
return Str::includes( 'wp-login.php', $url )
|
||||
|| Str::includes( 'wp-signup.php', $url )
|
||||
|| Str::includes( 'wp-activate.php', $url );
|
||||
|
||||
}
|
||||
|
||||
private function is_wp_login_action() {
|
||||
$actions = wpml_collect(
|
||||
[
|
||||
'confirm_admin_email',
|
||||
'postpass',
|
||||
'logout',
|
||||
'lostpassword',
|
||||
'retrievepassword',
|
||||
'resetpass',
|
||||
'rp',
|
||||
'register',
|
||||
'login',
|
||||
'confirmaction',
|
||||
]
|
||||
);
|
||||
|
||||
return $actions->contains( Obj::prop( 'action', $_GET ) );
|
||||
}
|
||||
|
||||
private function get_language_param_for_convert_url() {
|
||||
if ( isset( $_GET['lang'] ) ) {
|
||||
return Sanitize::stringProp( 'lang', $_GET );
|
||||
}
|
||||
if ( is_multisite() && isset( $_POST['lang'] ) ) {
|
||||
return Sanitize::stringProp( 'lang', $_POST );
|
||||
}
|
||||
if ( $this->rewrite_rule_not_found || $this->is_subdomain_multisite() ) {
|
||||
return $this->sitepress->get_current_language();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private function is_subdomain_multisite() {
|
||||
return is_multisite() && defined( 'SUBDOMAIN_INSTALL' ) && SUBDOMAIN_INSTALL;
|
||||
}
|
||||
|
||||
private function remove_language_directory_from_url( $url ) {
|
||||
$lang = $this->get_language_param_for_convert_url();
|
||||
$url_parts = wpml_parse_url( $url );
|
||||
if ( $lang && Str::includes( '/' . $lang . '/', $url_parts['path'] ) ) {
|
||||
$url = Str::replace( '/' . $lang . '/', '/', $url );
|
||||
}
|
||||
|
||||
return $url;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user