first commit
This commit is contained in:
@@ -0,0 +1,97 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Class WPML_Canonicals_Hooks
|
||||
*/
|
||||
class WPML_Canonicals_Hooks {
|
||||
|
||||
/** @var SitePress $sitepress */
|
||||
private $sitepress;
|
||||
|
||||
/** @var WPML_URL_Converter $url_converter */
|
||||
private $url_converter;
|
||||
|
||||
/** @var callable $is_current_request_root_callback */
|
||||
private $is_current_request_root_callback;
|
||||
|
||||
/**
|
||||
* WPML_Canonicals_Hooks constructor.
|
||||
*
|
||||
* @param SitePress $sitepress
|
||||
* @param WPML_URL_Converter $url_converter
|
||||
* @param callable $is_current_request_root_callback
|
||||
*/
|
||||
public function __construct( SitePress $sitepress, WPML_URL_Converter $url_converter, $is_current_request_root_callback ) {
|
||||
$this->sitepress = $sitepress;
|
||||
$this->url_converter = $url_converter;
|
||||
$this->is_current_request_root_callback = $is_current_request_root_callback;
|
||||
}
|
||||
|
||||
public function add_hooks() {
|
||||
$urls = $this->sitepress->get_setting( 'urls' );
|
||||
$lang_negotiation = (int) $this->sitepress->get_setting( 'language_negotiation_type' );
|
||||
|
||||
if ( WPML_LANGUAGE_NEGOTIATION_TYPE_DIRECTORY === $lang_negotiation
|
||||
&& ! empty( $urls['directory_for_default_language'] )
|
||||
) {
|
||||
add_action( 'template_redirect', array( $this, 'redirect_pages_from_root_to_default_lang_dir' ) );
|
||||
} elseif ( WPML_LANGUAGE_NEGOTIATION_TYPE_PARAMETER === $lang_negotiation ) {
|
||||
add_action( 'redirect_canonical', array( $this, 'prevent_redirection_with_translated_paged_content' ) );
|
||||
}
|
||||
|
||||
if ( isset( $_SERVER['SERVER_SOFTWARE'] ) && strpos( strtolower( $_SERVER['SERVER_SOFTWARE'] ), 'nginx' ) !== false ) {
|
||||
add_action( 'redirect_canonical', array( $this, 'maybe_fix_nginx_redirection_callback' ) );
|
||||
}
|
||||
}
|
||||
|
||||
public function redirect_pages_from_root_to_default_lang_dir() {
|
||||
global $wp_query;
|
||||
|
||||
if ( ( $wp_query->is_page() || $wp_query->is_posts_page ) && ! call_user_func( $this->is_current_request_root_callback ) ) {
|
||||
$lang = $this->sitepress->get_current_language();
|
||||
$current_uri = $_SERVER['REQUEST_URI'];
|
||||
$abs_home = $this->url_converter->get_abs_home();
|
||||
$install_subdir = wpml_parse_url( $abs_home, PHP_URL_PATH );
|
||||
$actual_uri = preg_replace( '#^' . $install_subdir . '#', '', $current_uri );
|
||||
$actual_uri = '/' . ltrim( $actual_uri, '/' );
|
||||
|
||||
if ( 0 !== strpos( $actual_uri, '/' . $lang ) ) {
|
||||
$canonical_uri = trailingslashit( $install_subdir ) . $lang . $actual_uri;
|
||||
$canonical_uri = user_trailingslashit( $canonical_uri );
|
||||
$this->sitepress->get_wp_api()->wp_safe_redirect( $canonical_uri, 301 );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $redirect
|
||||
*
|
||||
* @return bool|string
|
||||
*/
|
||||
public function maybe_fix_nginx_redirection_callback( $redirect ) {
|
||||
if ( is_front_page() ) {
|
||||
$redirect = false;
|
||||
}
|
||||
|
||||
return $redirect;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $redirect_url
|
||||
*
|
||||
* @return string|false
|
||||
*/
|
||||
public function prevent_redirection_with_translated_paged_content( $redirect_url ) {
|
||||
if ( ! is_singular() || ! isset( $_GET['lang'] ) ) {
|
||||
return $redirect_url;
|
||||
}
|
||||
|
||||
$page = (int) get_query_var( 'page' );
|
||||
|
||||
if ( $page < 2 ) {
|
||||
return $redirect_url;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,206 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @author OnTheGo Systems
|
||||
*/
|
||||
class WPML_Canonicals {
|
||||
const CANONICAL_FOR_DUPLICATED_POST = 'duplicate';
|
||||
const CANONICAL_FOR_NON_TRANSLATABLE_POST = 'non-translatable';
|
||||
/** @var SitePress */
|
||||
private $sitepress;
|
||||
/** @var WPML_Translations */
|
||||
private $wpml_translations;
|
||||
/** @var WPML_Translation_Element_Factory */
|
||||
private $translation_element_factory;
|
||||
|
||||
/**
|
||||
* WPML_Canonicals constructor.
|
||||
*
|
||||
* @param SitePress $sitepress
|
||||
* @param WPML_Translation_Element_Factory $translation_element_factory
|
||||
* @param WPML_Translations $wpml_translations
|
||||
*/
|
||||
public function __construct(
|
||||
SitePress $sitepress,
|
||||
WPML_Translation_Element_Factory $translation_element_factory,
|
||||
WPML_Translations $wpml_translations = null
|
||||
) {
|
||||
$this->sitepress = $sitepress;
|
||||
$this->translation_element_factory = $translation_element_factory;
|
||||
$this->wpml_translations = $wpml_translations;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $post_id
|
||||
*
|
||||
* @return bool|string
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
private function must_filter_permalink( $post_id ) {
|
||||
$this->init_wpml_translations();
|
||||
$post_element = $this->translation_element_factory->create( $post_id, 'post' );
|
||||
$must_handle_canonicals = $this->must_handle_a_canonical_url();
|
||||
|
||||
if ( $post_element->is_translatable() ) {
|
||||
if ( $must_handle_canonicals && $this->wpml_translations->is_a_duplicate_of( $post_element ) && $this->is_permalink_filter_from_rel_canonical() ) {
|
||||
return self::CANONICAL_FOR_DUPLICATED_POST;
|
||||
}
|
||||
} elseif ( $must_handle_canonicals ) {
|
||||
return self::CANONICAL_FOR_NON_TRANSLATABLE_POST;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $link
|
||||
* @param int $post_id
|
||||
*
|
||||
* @return null|string
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
public function permalink_filter( $link, $post_id ) {
|
||||
switch ( $this->must_filter_permalink( $post_id ) ) {
|
||||
case self::CANONICAL_FOR_DUPLICATED_POST:
|
||||
$post_element = $this->translation_element_factory->create( $post_id, 'post' );
|
||||
|
||||
return $this->get_canonical_of_duplicate( $post_element );
|
||||
|
||||
case self::CANONICAL_FOR_NON_TRANSLATABLE_POST:
|
||||
return $this->get_url_in_default_language_if_rel_canonical( $link );
|
||||
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $canonical_url
|
||||
* @param WP_Post $post
|
||||
*
|
||||
* @return string|bool
|
||||
*/
|
||||
public function get_canonical_url( $canonical_url, $post, $request_language ) {
|
||||
if ( $post && $this->sitepress->get_wp_api()->is_front_end() ) {
|
||||
try {
|
||||
/** @var WPML_Post_Element $post_element */
|
||||
$post_element = $this->translation_element_factory->create( $post->ID, 'post' );
|
||||
|
||||
$should_translate_canonical_url = apply_filters(
|
||||
'wpml_must_translate_canonical_url',
|
||||
true,
|
||||
$post_element
|
||||
);
|
||||
|
||||
if ( ! $should_translate_canonical_url ) {
|
||||
return $canonical_url;
|
||||
}
|
||||
|
||||
if ( ! $post_element->is_translatable() ) {
|
||||
global $wpml_url_filters;
|
||||
$wpml_url_filters->remove_global_hooks();
|
||||
$canonical_url = $this->sitepress->convert_url_string( $canonical_url, $this->sitepress->get_default_language() );
|
||||
$wpml_url_filters->add_global_hooks();
|
||||
} else {
|
||||
$this->init_wpml_translations();
|
||||
if ( $this->wpml_translations->is_a_duplicate_of( $post_element ) ) {
|
||||
$canonical_url = (string) $this->get_canonical_of_duplicate( $post_element );
|
||||
} elseif ( $post_element->get_language_code() != $request_language ) {
|
||||
$canonical_url = $this->sitepress->convert_url_string( $canonical_url, $post_element->get_language_code() );
|
||||
}
|
||||
}
|
||||
} catch ( InvalidArgumentException $e ) {
|
||||
}
|
||||
}
|
||||
|
||||
return $canonical_url;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $url
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_general_canonical_url( $url ) {
|
||||
global $wpml_url_filters;
|
||||
$wpml_url_filters->remove_global_hooks();
|
||||
$canonical_url = $this->sitepress->convert_url_string( $url, $this->sitepress->get_current_language() );
|
||||
$wpml_url_filters->add_global_hooks();
|
||||
|
||||
return $canonical_url;
|
||||
}
|
||||
|
||||
private function has_wp_get_canonical_url() {
|
||||
return $this->sitepress->get_wp_api()->function_exists( 'wp_get_canonical_url' );
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
private function is_permalink_filter_from_rel_canonical() {
|
||||
$back_trace_stack = $this->sitepress->get_wp_api()->get_backtrace( 20 );
|
||||
$keywords = array( 'rel_canonical', 'canonical', 'generate_canonical' );
|
||||
|
||||
$result = false;
|
||||
if ( $back_trace_stack ) {
|
||||
foreach ( $back_trace_stack as $key => $value ) {
|
||||
foreach ( $keywords as $keyword ) {
|
||||
if ( 'function' === $key && $keyword === $value ) {
|
||||
$result = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $link
|
||||
*
|
||||
* @return bool|string
|
||||
*/
|
||||
private function get_url_in_default_language_if_rel_canonical( $link ) {
|
||||
if ( $this->is_permalink_filter_from_rel_canonical() ) {
|
||||
$default_language = $this->sitepress->get_default_language();
|
||||
$link = (string) $this->sitepress->convert_url( $link, $default_language );
|
||||
}
|
||||
|
||||
return $link;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param WPML_Post_Element $post_element
|
||||
*
|
||||
* @return false|string
|
||||
*/
|
||||
private function get_canonical_of_duplicate( $post_element ) {
|
||||
$source_element = $post_element->get_source_element();
|
||||
if ( $source_element ) {
|
||||
$source_element_id = $source_element->get_id();
|
||||
$source_language_code = $source_element->get_language_code();
|
||||
$current_language = $this->sitepress->get_current_language();
|
||||
$this->sitepress->switch_lang( $source_language_code );
|
||||
$new_link = get_permalink( $source_element_id );
|
||||
$this->sitepress->switch_lang( $current_language );
|
||||
} else {
|
||||
$new_link = get_permalink( $post_element->get_id() );
|
||||
}
|
||||
|
||||
return $new_link;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
private function must_handle_a_canonical_url() {
|
||||
return ! $this->has_wp_get_canonical_url() && $this->sitepress->get_wp_api()->is_front_end();
|
||||
}
|
||||
|
||||
private function init_wpml_translations() {
|
||||
if ( ! $this->wpml_translations ) {
|
||||
$this->wpml_translations = new WPML_Translations( $this->sitepress );
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user