Files
doitinpoland.com/wp-content/plugins/wpml-string-translation/classes/slug-translation/class-wpml-slug-translation.php
2023-09-12 21:41:04 +02:00

392 lines
12 KiB
PHP

<?php
class WPML_Slug_Translation implements IWPML_Action {
const STRING_DOMAIN = 'WordPress';
/** @var array $post_link_cache */
private $post_link_cache = array();
/** @var SitePress $sitepress */
private $sitepress;
/** @var WPML_Slug_Translation_Records_Factory $slug_records_factory */
private $slug_records_factory;
/** @var WPML_ST_Term_Link_Filter $term_link_filter */
private $term_link_filter;
/** @var WPML_Get_LS_Languages_Status $ls_languages_status */
private $ls_languages_status;
/** @var WPML_ST_Slug_Translation_Settings $slug_translation_settings */
private $slug_translation_settings;
private $ignore_post_type_link = false;
public function __construct(
SitePress $sitepress,
WPML_Slug_Translation_Records_Factory $slug_records_factory,
WPML_Get_LS_Languages_Status $ls_language_status,
WPML_ST_Term_Link_Filter $term_link_filter,
WPML_ST_Slug_Translation_Settings $slug_translation_settings
) {
$this->sitepress = $sitepress;
$this->slug_records_factory = $slug_records_factory;
$this->ls_languages_status = $ls_language_status;
$this->term_link_filter = $term_link_filter;
$this->slug_translation_settings = $slug_translation_settings;
}
public function add_hooks() {
add_action( 'init', array( $this, 'init' ), WPML_Slug_Translation_Factory::INIT_PRIORITY );
}
public function init() {
$this->migrate_global_enabled_setting();
if ( $this->slug_translation_settings->is_enabled() ) {
add_filter( 'post_type_link', array( $this, 'post_type_link_filter' ), apply_filters( 'wpml_post_type_link_priority', 1 ), 4 );
add_filter( 'pre_term_link', array( $this->term_link_filter, 'replace_slug_in_termlink' ), 1, 2 ); // high priority
add_filter( 'edit_post', array( $this, 'clear_post_link_cache' ), 1, 2 );
add_filter( 'query_vars', array( $this, 'add_cpt_names' ), 1, 2 );
add_filter( 'pre_get_posts', array( $this, 'filter_pre_get_posts' ), - 1000, 2 );
}
if ( is_admin() ) {
add_action( 'icl_ajx_custom_call', array( $this, 'gui_save_options' ), 10, 2 );
add_action( 'wp_loaded', array( $this, 'maybe_migrate_string_name' ), 10, 0 );
}
}
/**
* @deprecated since 2.8.0, use the class `WPML_Post_Slug_Translation_Records` instead.
*
* @param string $type
*
* @return null|string
*/
public static function get_slug_by_type( $type ) {
$slug_records_factory = new WPML_Slug_Translation_Records_Factory();
$slug_records = $slug_records_factory->create( WPML_Slug_Translation_Factory::POST );
return $slug_records->get_original( $type );
}
/**
* This method is only for CPT
*
* @deprecated use `WPML_ST_Slug::filter_value` directly of the filter hook `wpml_get_translated_slug`
*
* @param string $slug_value
* @param string $post_type
* @param string|bool $language
*
* @return string
*/
public function get_translated_slug( $slug_value, $post_type, $language = false ) {
if ( $post_type ) {
$language = $language ? $language : $this->sitepress->get_current_language();
$slug = $this->slug_records_factory->create( WPML_Slug_Translation_Factory::POST )
->get_slug( $post_type );
return $slug->filter_value( $slug_value, $language );
}
return $slug_value;
}
/**
* @param array $value
*
* @return array
* @deprecated Use WPML\ST\SlugTranslation\Hooks\Hooks::filter
*/
public static function rewrite_rules_filter( $value ) {
return ( new \WPML\ST\SlugTranslation\Hooks\HooksFactory() )->create()->filter( $value );
}
/**
* @param string $post_link
* @param WP_Post $post
* @param bool $leavename
* @param bool $sample
*
* @return mixed|string|WP_Error
*/
public function post_type_link_filter( $post_link, $post, $leavename, $sample ) {
if ( $this->ignore_post_type_link ) {
return $post_link;
}
if ( ! $this->sitepress->is_translated_post_type( $post->post_type )
|| ! ( $ld = $this->sitepress->get_element_language_details( $post->ID, 'post_' . $post->post_type ) )
) {
return $post_link;
}
$ld = apply_filters( 'wpml_st_post_type_link_filter_language_details', $ld );
$cache_key = $leavename . '#' . $sample;
$cache_key .= $this->ls_languages_status->is_getting_ls_languages() ? 'yes' : 'no';
$cache_key .= $ld->language_code;
$blog_id = get_current_blog_id();
if ( isset( $this->post_link_cache[ $blog_id ][ $post->ID ][ $cache_key ] ) ) {
$post_link = $this->post_link_cache[ $blog_id ][ $post->ID ][ $cache_key ];
} else {
$slug_settings = $this->sitepress->get_setting( 'posts_slug_translation' );
$slug_settings = ! empty( $slug_settings['types'][ $post->post_type ] ) ? $slug_settings['types'][ $post->post_type ] : null;
if ( (bool) $slug_settings === true ) {
$post_type_obj = get_post_type_object( $post->post_type );
$slug_this = isset( $post_type_obj->rewrite['slug'] ) ? trim( $post_type_obj->rewrite['slug'], '/' ) : false;
$slug_real = $this->get_translated_slug( $slug_this, $post->post_type, $ld->language_code );
if ( empty( $slug_real ) || empty( $slug_this ) || $slug_this == $slug_real ) {
return $post_link;
}
global $wp_rewrite;
if ( isset( $wp_rewrite->extra_permastructs[ $post->post_type ] ) ) {
$struct_original = $wp_rewrite->extra_permastructs[ $post->post_type ]['struct'];
/**
* This hook allows to filter the slug we want to search and replace
* in the permalink structure. This is required for 3rd party
* plugins replacing the original slug with a placeholder.
*
* @since 3.1.0
*
* @param string $slug_this The original slug.
* @param string $post_link The initial link.
* @param WP_Post $post The post.
* @param bool $leavename Whether to keep the post name.
* @param bool $sample Is it a sample permalink.
*/
$slug_this = apply_filters( 'wpml_st_post_type_link_filter_original_slug', $slug_this, $post_link, $post, $leavename, $sample );
$lslash = false !== strpos( $struct_original, '/' . $slug_this ) ? '/' : '';
$wp_rewrite->extra_permastructs[ $post->post_type ]['struct'] = preg_replace(
'@' . $lslash . $slug_this . '/@',
$lslash . $slug_real . '/',
$struct_original
);
$this->ignore_post_type_link = true;
$post_link = get_post_permalink( $post->ID, $leavename, $sample );
$this->ignore_post_type_link = false;
$wp_rewrite->extra_permastructs[ $post->post_type ]['struct'] = $struct_original;
} else {
$post_link = str_replace( $slug_this . '=', $slug_real . '=', $post_link );
}
}
$this->post_link_cache[ $blog_id ][ $post->ID ][ $cache_key ] = $post_link;
}
return $post_link;
}
/**
* @param int $post_ID
* @param \WP_Post $post
*/
public function clear_post_link_cache( $post_ID, $post ) {
$blog_id = get_current_blog_id();
unset( $this->post_link_cache[ $blog_id ][ $post_ID ] );
}
/**
* @return array
*/
private function get_all_post_slug_translations() {
$slug_translations = array();
$post_slug_translation_settings = $this->sitepress->get_setting( 'posts_slug_translation' );
if ( isset( $post_slug_translation_settings['types'] ) ) {
$types = $post_slug_translation_settings['types'];
$cache_key = 'WPML_Slug_Translation::get_all_slug_translations' . md5( json_encode( $types ) );
$slug_translations = wp_cache_get( $cache_key );
if ( ! is_array( $slug_translations ) ) {
$slug_translations = array();
$types_to_fetch = array();
foreach ( $types as $type => $state ) {
if ( $state ) {
$types_to_fetch[] = str_replace( '%', '%%', $type );
}
}
if ( $types_to_fetch ) {
$data = $this->slug_records_factory
->create( WPML_Slug_Translation_Factory::POST )
->get_all_slug_translations( $types_to_fetch );
foreach ( $data as $row ) {
foreach ( $types_to_fetch as $type ) {
if ( preg_match( '#\s' . $type . '$#', $row->name ) === 1 ) {
$slug_translations[ $row->value ] = $type;
}
}
}
}
wp_cache_set( $cache_key, $slug_translations );
}
}
return $slug_translations;
}
/**
* Adds all translated custom post type slugs as valid query variables in addition to their original values
*
* @param array $qvars
*
* @return array
*/
public function add_cpt_names( $qvars ) {
$all_slugs_translations = array_keys( $this->get_all_post_slug_translations() );
$qvars = array_merge( $qvars, $all_slugs_translations );
return $qvars;
}
/**
* @param WP_Query $query
*
* @return WP_Query
*/
public function filter_pre_get_posts( $query ) {
/** Do not alter the query if it has already resolved the post ID */
if ( ! empty( $query->query_vars['p'] ) ) {
return $query;
}
$all_slugs_translations = $this->get_all_post_slug_translations();
foreach ( $query->query as $slug => $post_name ) {
if ( isset( $all_slugs_translations[ $slug ] ) ) {
$new_slug = isset( $all_slugs_translations[ $slug ] ) ? $all_slugs_translations[ $slug ] : $slug;
unset( $query->query[ $slug ] );
$query->query[ $new_slug ] = $post_name;
$query->query['name'] = $post_name;
$query->query['post_type'] = $new_slug;
unset( $query->query_vars[ $slug ] );
$query->query_vars[ $new_slug ] = $post_name;
$query->query_vars['name'] = $post_name;
$query->query_vars['post_type'] = $new_slug;
}
}
return $query;
}
/**
* @param string $action
*/
public static function gui_save_options( $action ) {
switch ( $action ) {
case 'icl_slug_translation':
global $sitepress;
$is_enabled = intval( ! empty( $_POST['icl_slug_translation_on'] ) );
$settings = new WPML_ST_Post_Slug_Translation_Settings( $sitepress );
$settings->set_enabled( $is_enabled );
echo '1|' . $is_enabled;
break;
}
}
/**
* @param string $slug
*
* @return string
*/
public static function sanitize( $slug ) {
// we need to preserve the %
$slug = str_replace( '%', '%45', $slug );
$slug = sanitize_title_with_dashes( $slug );
$slug = str_replace( '%45', '%', $slug );
/**
* Filters the sanitized post type or taxonomy slug translation
*
* @since 2.10.0
*
* @param string $slug
*/
return apply_filters( 'wpml_st_slug_translation_sanitize', $slug );
}
/**
* @deprecated since 2.8.0, use the class `WPML_Post_Slug_Translation_Records` instead.
*/
public static function register_string_for_slug( $post_type, $slug ) {
return icl_register_string( self::STRING_DOMAIN, 'URL slug: ' . $post_type, $slug );
}
public function maybe_migrate_string_name() {
global $wpdb;
$slug_settings = $this->sitepress->get_setting( 'posts_slug_translation' );
if ( ! isset( $slug_settings['string_name_migrated'] ) ) {
$queryable_post_types = get_post_types( array( 'publicly_queryable' => true ) );
foreach ( $queryable_post_types as $type ) {
$post_type_obj = get_post_type_object( $type );
if ( null === $post_type_obj || ! isset( $post_type_obj->rewrite['slug'] ) ) {
continue;
}
$slug = trim( $post_type_obj->rewrite['slug'], '/' );
if ( $slug ) {
// First check if we should migrate from the old format URL slug: slug
$string_id = $wpdb->get_var(
$wpdb->prepare(
"SELECT id
FROM {$wpdb->prefix}icl_strings
WHERE name = %s AND value = %s",
'URL slug: ' . $slug,
$slug
)
);
if ( $string_id ) {
// migrate it to URL slug: post_type
$st_update['name'] = 'URL slug: ' . $type;
$wpdb->update( $wpdb->prefix . 'icl_strings', $st_update, array( 'id' => $string_id ) );
}
}
}
$slug_settings['string_name_migrated'] = true;
$this->sitepress->set_setting( 'posts_slug_translation', $slug_settings, true );
}
}
/**
* Move global on/off setting to its own option WPML_ST_Slug_Translation_Settings::KEY_ENABLED_GLOBALLY
*/
private function migrate_global_enabled_setting() {
$enabled = get_option( WPML_ST_Slug_Translation_Settings::KEY_ENABLED_GLOBALLY );
if ( false === $enabled ) {
$old_setting = $this->sitepress->get_setting( WPML_ST_Post_Slug_Translation_Settings::KEY_IN_SITEPRESS_SETTINGS );
if ( array_key_exists( 'on', $old_setting ) ) {
$enabled = (int) $old_setting['on'];
} else {
$enabled = 0;
}
update_option( WPML_ST_Slug_Translation_Settings::KEY_ENABLED_GLOBALLY, $enabled );
}
}
}