280 lines
7.7 KiB
PHP
280 lines
7.7 KiB
PHP
<?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;
|
|
}
|
|
}
|