'code', 'hide_current' => '', 'hide_missing' => '', ), is_array( $atts ) ? $atts : array(), self::SHORTCODE ); $display = (string) $atts['display']; wp_enqueue_style( 'blocklingo-switcher' ); return $this->render( array( 'display' => in_array( $display, self::displays(), true ) ? $display : 'code', 'hideCurrent' => self::truthy( $atts['hide_current'] ), 'hideMissing' => self::truthy( $atts['hide_missing'] ), ) ); } /** "1", "true", "yes", "on" -> true. */ private static function truthy( mixed $value ): bool { return in_array( strtolower( trim( (string) $value ) ), array( '1', 'true', 'yes', 'on' ), true ); } /** @return string[] How each language is shown. */ public static function displays(): array { return array( 'code', 'name', 'flag', 'flag-code', 'flag-name' ); } /** @return array> */ public static function attributes(): array { return array( 'display' => array( 'type' => 'string', 'enum' => self::displays(), 'default' => 'code', ), 'hideCurrent' => array( 'type' => 'boolean', 'default' => false, ), 'hideMissing' => array( 'type' => 'boolean', 'default' => false, ), 'className' => array( 'type' => 'string' ), ); } public function register_block(): void { wp_register_style( 'blocklingo-switcher', BLOCKLINGO_URL . 'assets/switcher.css', array(), BLOCKLINGO_VERSION ); wp_register_script( 'blocklingo-switcher-editor', BLOCKLINGO_URL . 'assets/switcher.js', array( 'wp-blocks', 'wp-element', 'wp-components', 'wp-block-editor', 'wp-server-side-render', 'wp-i18n' ), BLOCKLINGO_VERSION . '.' . (string) filemtime( BLOCKLINGO_DIR . 'assets/switcher.js' ), true ); wp_set_script_translations( 'blocklingo-switcher-editor', 'blocklingo', BLOCKLINGO_DIR . 'languages' ); register_block_type( self::NAME, array( 'api_version' => '3', 'title' => __( 'Language switcher', 'blocklingo' ), 'category' => 'widgets', 'icon' => 'translation', 'description' => __( 'Links to this page in the other languages.', 'blocklingo' ), 'attributes' => self::attributes(), 'supports' => array( 'html' => false, 'typography' => array( 'fontSize' => true ), 'spacing' => array( 'margin' => true ), ), 'editor_script' => 'blocklingo-switcher-editor', 'style' => 'blocklingo-switcher', 'render_callback' => \AddBlack\Lang\Failsafe::guard( array( $this, 'render' ), 'block ' . self::NAME, false ), ) ); } /** * Items for the current request: lang => url, name, flag, locale, current, missing. * * @return array */ public function items(): array { $settings = $this->settings->get(); $current = $this->current->get(); $current = '' !== $current ? $current : $settings->default_code(); $alts = $this->alternates->current_page(); // Home pages exist in every language, so nothing is "missing" there. $special = is_front_page() || ( is_home() && ! get_option( 'page_for_posts' ) ); $out = array(); foreach ( $settings->languages() as $code => $lang ) { $code = (string) $code; $has = isset( $alts[ $code ] ); $out[ $code ] = array( 'url' => $has ? $alts[ $code ] : $this->urls->lang_home( $code ), 'name' => $lang->name, 'flag' => $lang->flag, 'locale' => $lang->locale, 'current' => $code === $current, 'missing' => ! $has && ! $special && $code !== $current, ); } return $out; } /** * The links to show, after the hide options: label HTML is escaped. * * @param array $attributes Block attributes (display, hideCurrent, hideMissing). * @return list */ public function links( array $attributes = array() ): array { $defaults = array(); foreach ( self::attributes() as $name => $def ) { if ( array_key_exists( 'default', $def ) ) { $defaults[ $name ] = $def['default']; } } $attributes = wp_parse_args( $attributes, $defaults ); $out = array(); foreach ( $this->items() as $code => $item ) { if ( ( $item['current'] && $attributes['hideCurrent'] ) || ( $item['missing'] && $attributes['hideMissing'] ) ) { continue; } $label = self::label( $code, $item, (string) $attributes['display'] ); $out[] = array( 'code' => $code, 'url' => $item['url'], 'hreflang' => str_replace( '_', '-', '' !== $item['locale'] ? $item['locale'] : $code ), 'current' => $item['current'], 'html' => $label['html'], 'aria' => $label['aria'], ); } return $out; } /** * The switcher HTML. Also used by the blocklingo_language_switcher template tag. * * @param array $attributes Block attributes. */ public function render( array $attributes = array() ): string { $li = ''; foreach ( $this->links( $attributes ) as $link ) { $li .= sprintf( '
  • %6$s
  • ', $link['current'] ? ' is-current' : '', esc_url( $link['url'] ), esc_attr( $link['hreflang'] ), $link['current'] ? ' aria-current="true"' : '', '' !== $link['aria'] ? ' aria-label="' . esc_attr( $link['aria'] ) . '"' : '', $link['html'] ); } if ( '' === $li ) { return ''; } $wrapper = \WP_Block_Supports::$block_to_render ? get_block_wrapper_attributes( array( 'class' => 'blocklingo-switcher' ) ) : 'class="blocklingo-switcher"'; return ''; } /** * @param array{name: string, flag: string} $item * @return array{html: string, aria: string} */ private static function label( string $code, array $item, string $display ): array { $code_txt = esc_html( strtoupper( $code ) ); $name = esc_html( $item['name'] ); $flag = '' !== $item['flag'] ? '' : ''; return match ( $display ) { 'name' => array( 'html' => $name, 'aria' => '', ), 'flag' => array( 'html' => '' !== $flag ? $flag : $code_txt, 'aria' => $item['name'], ), 'flag-code' => array( 'html' => $flag . $code_txt, 'aria' => $item['name'], ), 'flag-name' => array( 'html' => $flag . $name, 'aria' => '', ), default => array( 'html' => $code_txt, 'aria' => $item['name'], ), }; } }