491 lines
14 KiB
PHP
491 lines
14 KiB
PHP
<?php
|
|
|
|
class WPML_LS_Model_Build extends WPML_SP_User {
|
|
|
|
const LINK_CSS_CLASS = 'wpml-ls-link';
|
|
|
|
/* @var WPML_LS_Settings $settings */
|
|
private $settings;
|
|
|
|
/* @var WPML_Mobile_Detect $mobile_detect */
|
|
private $mobile_detect;
|
|
|
|
/* @var bool $is_touch_screen */
|
|
private $is_touch_screen = false;
|
|
|
|
/* @var string $css_prefix */
|
|
private $css_prefix;
|
|
|
|
private $allowed_vars = [
|
|
'languages' => 'array',
|
|
'current_language_code' => 'string',
|
|
'css_classes' => 'string',
|
|
'css_classes_link' => 'string',
|
|
'backward_compatibility' => 'array',
|
|
];
|
|
|
|
private $allowed_language_vars = [
|
|
'code' => 'string',
|
|
'url' => 'string',
|
|
'flag_url' => 'string',
|
|
'flag_title' => 'string',
|
|
'flag_alt' => 'string',
|
|
'native_name' => 'string',
|
|
'display_name' => 'string',
|
|
'is_current' => 'bool',
|
|
'css_classes' => 'string',
|
|
'db_id' => 'string',
|
|
'menu_item_parent' => 'mixed',
|
|
'is_parent' => 'bool',
|
|
'backward_compatibility' => 'array',
|
|
'flag_width' => 'int',
|
|
'flag_height' => 'int',
|
|
];
|
|
|
|
/**
|
|
* WPML_Language_Switcher_Render_Model constructor.
|
|
*
|
|
* @param WPML_LS_Settings $settings
|
|
* @param SitePress $sitepress
|
|
* @param string $css_prefix
|
|
*/
|
|
public function __construct( $settings, $sitepress, $css_prefix ) {
|
|
$this->settings = $settings;
|
|
$this->css_prefix = $css_prefix;
|
|
parent::__construct( $sitepress );
|
|
}
|
|
|
|
/**
|
|
* @param WPML_LS_Slot $slot
|
|
* @param array $template_data
|
|
*
|
|
* @return array
|
|
*/
|
|
public function get( $slot, $template_data = [] ) {
|
|
$vars = [];
|
|
|
|
$vars['current_language_code'] = $this->sitepress->get_current_language();
|
|
$vars['languages'] = $this->get_language_items( $slot, $template_data );
|
|
$vars['css_classes'] = $this->get_slot_css_classes( $slot );
|
|
$vars['css_classes_link'] = self::LINK_CSS_CLASS;
|
|
|
|
$vars = $this->add_backward_compatibility_to_wrapper( $vars, $slot );
|
|
|
|
return $this->sanitize_vars( $vars, $this->allowed_vars );
|
|
}
|
|
|
|
/**
|
|
* @param WPML_LS_Slot $slot
|
|
*
|
|
* @return string
|
|
*/
|
|
public function get_slot_css_classes( $slot ) {
|
|
$classes = [ $this->get_slot_css_main_class( $slot->group(), $slot->slug() ) ];
|
|
|
|
$classes[] = trim( $this->css_prefix, '-' );
|
|
|
|
if ( $this->sitepress->is_rtl( $this->sitepress->get_current_language() ) ) {
|
|
$classes[] = $this->css_prefix . 'rtl';
|
|
}
|
|
|
|
$classes = $this->add_user_agent_touch_device_classes( $classes );
|
|
|
|
/**
|
|
* Filter the css classes for the language switcher wrapper
|
|
* The wrapper is not available for menus
|
|
*
|
|
* @param array $classes
|
|
*/
|
|
$classes = apply_filters( 'wpml_ls_model_css_classes', $classes );
|
|
|
|
return implode( ' ', $classes );
|
|
}
|
|
|
|
/**
|
|
* @param string $group
|
|
* @param string $slug
|
|
*
|
|
* @return string
|
|
*/
|
|
public function get_slot_css_main_class( $group, $slug ) {
|
|
return $this->css_prefix . $group . '-' . $slug;
|
|
}
|
|
|
|
/**
|
|
* @return string
|
|
*/
|
|
public function get_css_prefix() {
|
|
return $this->css_prefix;
|
|
}
|
|
|
|
/**
|
|
* @param WPML_LS_Slot $slot
|
|
* @param array $template_data
|
|
*
|
|
* @return array
|
|
*/
|
|
private function get_language_items( $slot, $template_data ) {
|
|
$ret = [];
|
|
|
|
|
|
$get_ls_args = [
|
|
'skip_missing' => ! $this->settings->get_setting( 'link_empty' ),
|
|
];
|
|
|
|
if ( $slot->is_post_translations() ) {
|
|
$get_ls_args['skip_missing'] = true;
|
|
} elseif ( ( WPML_Root_Page::uses_html_root() || WPML_Root_Page::get_root_id() ) && WPML_Root_Page::is_current_request_root() ) {
|
|
$get_ls_args['skip_missing'] = false;
|
|
}
|
|
|
|
$flag_width = $slot->get( 'include_flag_width' );
|
|
$flag_height = $slot->get( 'include_flag_height' );
|
|
|
|
$languages = $this->sitepress->get_ls_languages( $get_ls_args );
|
|
$languages = is_array( $languages ) ? $languages : [];
|
|
|
|
$languages = $this->order_languages( $languages, $this->sitepress->get_current_language() );
|
|
|
|
if ( $languages ) {
|
|
|
|
foreach ( $languages as $code => $data ) {
|
|
|
|
$is_current_language = $code === $this->sitepress->get_current_language();
|
|
|
|
if ( ! $slot->get( 'display_link_for_current_lang' ) && $is_current_language ) {
|
|
continue;
|
|
}
|
|
|
|
$ret[ $code ] = [
|
|
'code' => $code,
|
|
'url' => $data['url'],
|
|
];
|
|
|
|
if ( $flag_width ) {
|
|
$ret[ $code ]['flag_width'] = $flag_width;
|
|
}
|
|
if ( $flag_height ) {
|
|
$ret[ $code ]['flag_height'] = $flag_height;
|
|
}
|
|
|
|
/* @deprecated Use 'wpml_ls_language_url' instead */
|
|
$ret[ $code ]['url'] = apply_filters( 'WPML_filter_link', $ret[ $code ]['url'], $data );
|
|
|
|
/**
|
|
* This filter allows to change the URL for each languages links in the switcher
|
|
*
|
|
* @param string $ret [ $code ]['url'] The language URL to be filtered
|
|
* @param array $data The language information
|
|
*/
|
|
$ret[ $code ]['url'] = apply_filters( 'wpml_ls_language_url', $ret[ $code ]['url'], $data );
|
|
|
|
$ret[ $code ]['url'] = $this->sitepress->get_wp_api()->is_admin() ? '#' : $ret[ $code ]['url'];
|
|
|
|
$css_classes = $this->get_language_css_classes( $slot, $code );
|
|
|
|
$display_native = $slot->get( 'display_names_in_native_lang' );
|
|
$display_name = $slot->get( 'display_names_in_current_lang' );
|
|
|
|
if ( $slot->get( 'display_flags' ) ) {
|
|
$ret[ $code ]['flag_url'] = $this->filter_flag_url( $data['country_flag_url'], $template_data );
|
|
$ret[ $code ]['flag_title'] = $data['native_name'];
|
|
$ret[ $code ]['flag_alt'] = ( $display_name || $display_native ) ? '' : $data['translated_name'];
|
|
}
|
|
|
|
if ( $display_native ) {
|
|
$ret[ $code ]['native_name'] = $data['native_name'];
|
|
}
|
|
|
|
if ( $display_name ) {
|
|
$ret[ $code ]['display_name'] = $data['translated_name'];
|
|
}
|
|
|
|
if ( $is_current_language ) {
|
|
$ret[ $code ]['is_current'] = true;
|
|
array_push( $css_classes, $this->css_prefix . 'current-language' );
|
|
}
|
|
|
|
if ( $slot->is_menu() ) {
|
|
$ret[ $code ]['db_id'] = $this->get_menu_item_id( $code, $slot );
|
|
$ret[ $code ]['menu_item_parent'] = $slot->get( 'is_hierarchical' ) && ! $is_current_language && $slot->get( 'display_link_for_current_lang' )
|
|
? $this->get_menu_item_id( $this->sitepress->get_current_language(), $slot ) : 0;
|
|
$ret[ $code ]['is_parent'] = $slot->get( 'is_hierarchical' ) && $is_current_language;
|
|
|
|
array_unshift( $css_classes, 'menu-item' );
|
|
array_push( $css_classes, $this->css_prefix . 'menu-item' );
|
|
}
|
|
|
|
$ret[ $code ]['css_classes'] = $css_classes;
|
|
}
|
|
|
|
$i = 1;
|
|
foreach ( $ret as &$lang ) {
|
|
if ( $i === 1 ) {
|
|
array_push( $lang['css_classes'], $this->css_prefix . 'first-item' );
|
|
}
|
|
|
|
if ( $i === count( $ret ) ) {
|
|
array_push( $lang['css_classes'], $this->css_prefix . 'last-item' );
|
|
}
|
|
|
|
$lang = $this->add_backward_compatibility_to_languages( $lang, $slot );
|
|
|
|
/**
|
|
* Filter the css classes for each language item
|
|
*
|
|
* @param array $lang ['css_classes']
|
|
*/
|
|
$lang['css_classes'] = apply_filters( 'wpml_ls_model_language_css_classes', $lang['css_classes'] );
|
|
|
|
$lang['css_classes'] = implode( ' ', $lang['css_classes'] );
|
|
|
|
$lang = $this->sanitize_vars( $lang, $this->allowed_language_vars );
|
|
$i++;
|
|
}
|
|
}
|
|
|
|
return $ret;
|
|
}
|
|
|
|
/**
|
|
* @param array $languages
|
|
*
|
|
* @return array
|
|
*/
|
|
private function order_languages( $languages, $current_language ) {
|
|
if ( isset( $languages[$current_language] ) ) {
|
|
$current_language_value = $languages[$current_language];
|
|
unset($languages[$current_language]);
|
|
return array_merge([$current_language => $current_language_value], $languages);
|
|
} else {
|
|
return $languages;
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
* @param string $url
|
|
* @param array $template_data
|
|
*
|
|
* @return string
|
|
*/
|
|
private function filter_flag_url( $url, $template_data = [] ) {
|
|
$wp_upload_dir = wp_upload_dir();
|
|
$has_custom_flag = strpos( $url, $wp_upload_dir['baseurl'] . '/flags/' ) === 0 ? true : false;
|
|
|
|
if ( ! $has_custom_flag && ! empty( $template_data['flags_base_uri'] ) ) {
|
|
$url = trailingslashit( $template_data['flags_base_uri'] ) . basename( $url );
|
|
|
|
if ( isset( $template_data['flag_extension'] ) ) {
|
|
$old_ext = pathinfo( $url, PATHINFO_EXTENSION );
|
|
$url = preg_replace( '#' . $old_ext . '$#', $template_data['flag_extension'], $url, 1 );
|
|
}
|
|
}
|
|
|
|
return $url;
|
|
}
|
|
|
|
/**
|
|
* @param WPML_LS_Slot $slot
|
|
* @param string $code
|
|
*
|
|
* @return array
|
|
*/
|
|
private function get_language_css_classes( $slot, $code ) {
|
|
return [
|
|
$this->css_prefix . 'slot-' . $slot->slug(),
|
|
$this->css_prefix . 'item',
|
|
$this->css_prefix . 'item-' . $code,
|
|
];
|
|
}
|
|
|
|
/**
|
|
* @param array $classes
|
|
*
|
|
* @return array
|
|
*/
|
|
private function add_user_agent_touch_device_classes( $classes ) {
|
|
|
|
if ( is_null( $this->mobile_detect ) ) {
|
|
require_once WPML_PLUGIN_PATH . '/lib/mobile-detect.php';
|
|
$this->mobile_detect = new WPML_Mobile_Detect();
|
|
$this->is_touch_screen = $this->mobile_detect->isMobile() || $this->mobile_detect->isTablet();
|
|
}
|
|
|
|
if ( $this->is_touch_screen ) {
|
|
$classes[] = $this->css_prefix . 'touch-device';
|
|
}
|
|
|
|
return $classes;
|
|
}
|
|
|
|
/**
|
|
* @return bool
|
|
*/
|
|
private function needs_backward_compatibility() {
|
|
return (bool) $this->settings->get_setting( 'migrated' );
|
|
}
|
|
|
|
/**
|
|
* @param string $code
|
|
* @param WPML_LS_Slot $slot
|
|
*
|
|
* @return string
|
|
*/
|
|
private function get_menu_item_id( $code, $slot ) {
|
|
return $this->css_prefix . $slot->slug() . '-' . $code;
|
|
}
|
|
|
|
/**
|
|
* @param array $vars
|
|
* @param array $allowed_vars
|
|
*
|
|
* @return array
|
|
*/
|
|
private function sanitize_vars( $vars, $allowed_vars ) {
|
|
$sanitized = [];
|
|
|
|
foreach ( $allowed_vars as $allowed_var => $type ) {
|
|
if ( isset( $vars[ $allowed_var ] ) ) {
|
|
switch ( $type ) {
|
|
case 'array':
|
|
$sanitized[ $allowed_var ] = (array) $vars[ $allowed_var ];
|
|
break;
|
|
|
|
case 'string':
|
|
$sanitized[ $allowed_var ] = (string) $vars[ $allowed_var ];
|
|
break;
|
|
|
|
case 'int':
|
|
$sanitized[ $allowed_var ] = (int) $vars[ $allowed_var ];
|
|
break;
|
|
|
|
case 'bool':
|
|
$sanitized[ $allowed_var ] = (bool) $vars[ $allowed_var ];
|
|
break;
|
|
|
|
case 'mixed':
|
|
$sanitized[ $allowed_var ] = $vars[ $allowed_var ];
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return $sanitized;
|
|
}
|
|
|
|
/**
|
|
* @param array $lang
|
|
* @param WPML_LS_Slot $slot
|
|
*
|
|
* @return array
|
|
*/
|
|
private function add_backward_compatibility_to_languages( $lang, $slot ) {
|
|
|
|
if ( $this->needs_backward_compatibility() ) {
|
|
|
|
$is_current_language = isset( $lang['is_current'] ) && $lang['is_current'];
|
|
|
|
if ( $slot->is_menu() ) {
|
|
|
|
if ( $is_current_language ) {
|
|
array_unshift( $lang['css_classes'], 'menu-item-language-current' );
|
|
}
|
|
|
|
array_unshift( $lang['css_classes'], 'menu-item-language' );
|
|
}
|
|
|
|
if ( $slot->is_sidebar() || $slot->is_shortcode_actions() ) {
|
|
|
|
if ( $this->is_legacy_template( $slot->template(), 'list-vertical' )
|
|
|| $this->is_legacy_template( $slot->template(), 'list-horizontal' )
|
|
) {
|
|
array_unshift( $lang['css_classes'], 'icl-' . $lang['code'] );
|
|
$lang['backward_compatibility']['css_classes_a'] = $is_current_language ?
|
|
'lang_sel_sel' : 'lang_sel_other';
|
|
}
|
|
|
|
if ( $this->is_legacy_template( $slot->template(), 'dropdown' )
|
|
|| $this->is_legacy_template( $slot->template(), 'dropdown-click' )
|
|
) {
|
|
|
|
if ( $is_current_language ) {
|
|
$lang['backward_compatibility']['css_classes_a'] = 'lang_sel_sel icl-' . $lang['code'];
|
|
} else {
|
|
array_unshift( $lang['css_classes'], 'icl-' . $lang['code'] );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return $lang;
|
|
}
|
|
|
|
/**
|
|
* @param array $vars
|
|
* @param WPML_LS_Slot $slot
|
|
*
|
|
* @return mixed
|
|
*/
|
|
private function add_backward_compatibility_to_wrapper( $vars, $slot ) {
|
|
|
|
if ( $this->needs_backward_compatibility() ) {
|
|
|
|
if ( $slot->is_sidebar() || $slot->is_shortcode_actions() ) {
|
|
|
|
if ( $this->is_legacy_template( $slot->template(), 'list-vertical' )
|
|
|| $this->is_legacy_template( $slot->template(), 'list-horizontal' )
|
|
) {
|
|
$vars['backward_compatibility']['css_id'] = 'lang_sel_list';
|
|
|
|
if ( $this->is_legacy_template( $slot->template(), 'list-horizontal' ) ) {
|
|
$vars['css_classes'] = 'lang_sel_list_horizontal ' . $vars['css_classes'];
|
|
} else {
|
|
$vars['css_classes'] = 'lang_sel_list_vertical ' . $vars['css_classes'];
|
|
}
|
|
}
|
|
|
|
if ( $this->is_legacy_template( $slot->template(), 'dropdown' ) ) {
|
|
$vars['backward_compatibility']['css_id'] = 'lang_sel';
|
|
}
|
|
|
|
if ( $this->is_legacy_template( $slot->template(), 'dropdown-click' ) ) {
|
|
$vars['backward_compatibility']['css_id'] = 'lang_sel_click';
|
|
}
|
|
}
|
|
|
|
if ( $slot->is_post_translations() ) {
|
|
$vars['css_classes'] = 'icl_post_in_other_langs ' . $vars['css_classes'];
|
|
}
|
|
|
|
if ( $slot->is_footer() ) {
|
|
$vars['backward_compatibility']['css_id'] = 'lang_sel_footer';
|
|
}
|
|
|
|
$vars['backward_compatibility']['css_classes_flag'] = 'iclflag';
|
|
$vars['backward_compatibility']['css_classes_native'] = 'icl_lang_sel_native';
|
|
$vars['backward_compatibility']['css_classes_display'] = 'icl_lang_sel_translated';
|
|
$vars['backward_compatibility']['css_classes_bracket'] = 'icl_lang_sel_bracket';
|
|
}
|
|
|
|
return $vars;
|
|
}
|
|
|
|
/**
|
|
* @param string $template_slug
|
|
* @param string|null $type
|
|
*
|
|
* @return bool
|
|
*/
|
|
private function is_legacy_template( $template_slug, $type = null ) {
|
|
$templates = $this->settings->get_core_templates();
|
|
$ret = in_array( $template_slug, $templates, true );
|
|
|
|
if ( $ret && array_key_exists( $type, $templates ) ) {
|
|
$ret = $templates[ $type ] === $template_slug;
|
|
}
|
|
|
|
return $ret;
|
|
}
|
|
}
|