[ 'class' => true, 'style' => true, 'role' => true, 'aria-label' => true ],
'button' => [ 'type' => true, 'class' => true, 'aria-haspopup' => true, 'aria-expanded' => true ],
'span' => [ 'class' => true, 'style' => true, 'aria-hidden' => true ],
'ul' => [ 'class' => true ],
'li' => [ 'class' => true ],
'a' => [ 'class' => true, 'href' => true, 'title' => true, 'rel' => true, 'target' => true ],
'img' => [ 'src' => true, 'class' => true, 'alt' => true, 'width' => true, 'height' => true, 'srcset' => true, 'sizes' => true, 'loading' => true, 'decoding' => true, 'style' => true ],
];
}
public function hooks() {
add_shortcode( 'abdiel_language_switcher', [ $this, 'shortcode' ] );
add_action( 'wp_footer', [ $this, 'maybe_render_floating' ] );
add_filter( 'wp_nav_menu_items', [ $this, 'maybe_append_menu_switcher' ], 10, 2 );
add_action( 'wp_enqueue_scripts', [ $this, 'assets' ] );
}
public function assets() {
wp_enqueue_style( 'abdiel-amm-frontend', ABDIEL_AMM_URL . 'assets/frontend.css', [], ABDIEL_AMM_VERSION );
wp_enqueue_script( 'abdiel-amm-frontend', ABDIEL_AMM_URL . 'assets/frontend.js', [], ABDIEL_AMM_VERSION, true );
}
public function shortcode( $atts = [] ) {
$atts = shortcode_atts( [
'show' => 'auto', // auto|all
], $atts, 'abdiel_language_switcher' );
return $this->render( [
'context' => 'shortcode',
'show' => $atts['show'],
] );
}
public function maybe_append_menu_switcher( $items, $args ) {
$settings = Settings::get_settings_option();
if ( $settings['switcher_mode'] !== 'menu' ) { return $items; }
// Optional: restrict by theme location.
if ( ! empty( $settings['menu_location'] ) && isset( $args->theme_location ) ) {
if ( $args->theme_location !== $settings['menu_location'] ) { return $items; }
}
// Optional: restrict by specific menu term ID.
if ( ! empty( $settings['menu_term_id'] ) ) {
$menu_id = 0;
if ( isset( $args->menu ) ) {
if ( is_object( $args->menu ) && isset( $args->menu->term_id ) ) { $menu_id = (int) $args->menu->term_id; }
if ( is_numeric( $args->menu ) ) { $menu_id = (int) $args->menu; }
}
if ( $menu_id && (int) $settings['menu_term_id'] !== $menu_id ) { return $items; }
}
$switcher = $this->render( [
'context' => 'menu',
'show' => 'auto',
] );
if ( empty( $switcher ) ) { return $items; }
$items .= '
';
return $items;
}
public function maybe_render_floating() {
$settings = Settings::get_settings_option();
if ( $settings['switcher_mode'] !== 'floating' ) { return; }
// Escape late: output is HTML, so we whitelist expected tags/attributes.
echo wp_kses( $this->render( [
'context' => 'floating',
'show' => 'auto',
] ), $this->kses_allowed_html() );
}
private function get_lang_manager() {
return abdiel_amm_boot()->content;
}
private function get_languages() {
$langs = Settings::get_languages_option();
$items = $langs['items'];
uasort( $items, function( $a, $b ) { return (int) $a['order'] <=> (int) $b['order']; } );
$langs['items'] = $items;
return $langs;
}
public function render( $args = [] ) {
$settings = Settings::get_settings_option();
$content = $this->get_lang_manager();
$langs = $this->get_languages();
$active = [];
foreach ( (array) $langs['items'] as $code => $row ) {
if ( ! empty( $row['active'] ) ) { $active[ $code ] = $row; }
}
if ( count( $active ) <= 1 ) { return ''; }
$current_id = get_queried_object_id();
$current_code = $content->get_current_language_code( $current_id );
$map = $content->get_translation_map( $current_id );
// Only show languages that have a linked post/page AND are published.
$visible = [];
foreach ( $active as $code => $row ) {
if ( $args['show'] === 'all' ) {
$visible[ $code ] = $row;
continue;
}
if ( empty( $map[ $code ] ) ) { continue; }
$pid = absint( $map[ $code ] );
if ( $pid <= 0 ) { continue; }
if ( get_post_status( $pid ) !== 'publish' ) { continue; }
$visible[ $code ] = $row;
}
if ( count( $visible ) <= 1 ) { return ''; }
// Build inline CSS variables so user-defined colors always take precedence.
$style_vars = [];
if ( ! empty( $settings['btn_bg'] ) ) { $style_vars[] = '--abdiel-amm-btn-bg:' . $settings['btn_bg']; }
if ( ! empty( $settings['btn_text'] ) ) { $style_vars[] = '--abdiel-amm-btn-text:' . $settings['btn_text']; }
if ( ! empty( $settings['btn_bg_hover'] ) ) { $style_vars[] = '--abdiel-amm-btn-bg-hover:' . $settings['btn_bg_hover']; }
if ( ! empty( $settings['btn_text_hover'] ) ) { $style_vars[] = '--abdiel-amm-btn-text-hover:' . $settings['btn_text_hover']; }
$style_attr = ! empty( $style_vars ) ? ' style="' . esc_attr( implode( ';', $style_vars ) ) . '"' : '';
$classes = [ 'abdiel-amm-switcher', 'abdiel-amm-context-' . sanitize_html_class( $args['context'] ) ];
if ( $args['context'] === 'floating' ) {
$classes[] = 'abdiel-amm-pos-' . sanitize_html_class( $settings['floating_position'] );
}
ob_start();
?>
role="navigation" aria-label="">
content->get_default_language_code();
$url = $target_post_id ? get_permalink( $target_post_id ) : home_url( '/' );
if ( $mode === 'query' ) {
if ( $default && $lang_code === $default ) { return $url; }
return add_query_arg( 'lang', $lang_code, $url );
}
if ( $mode === 'prefix' ) {
if ( $default && $lang_code === $default ) { return $url; }
$parsed = wp_parse_url( $url );
$host = ( isset( $parsed['scheme'] ) ? $parsed['scheme'] . '://' : '' ) . ( $parsed['host'] ?? '' );
if ( isset( $parsed['port'] ) ) { $host .= ':' . $parsed['port']; }
$path = $parsed['path'] ?? '/';
$path = '/' . ltrim( $path, '/' );
// remove existing lang prefix
$path = preg_replace( '#^/([a-z]{2})(/|$)#i', '/', $path, 1 );
$path = '/' . $lang_code . rtrim( $path, '/' );
if ( substr( $path, -1 ) !== '/' ) { $path .= '/'; }
return $host . $path;
}
return $url;
}
}