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 ); } } }